1 /***************************************************************************
4 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
11 * Copyright (C) 2002 Gilles Roux, 2003 Garrett Derner
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
24 #include "lib/playback_control.h"
25 #include "lib/oldmenuapi.h"
29 #define SETTINGS_FILE VIEWERS_DIR "/viewer.dat" /* binary file, so dont use .cfg */
30 #define BOOKMARKS_FILE VIEWERS_DIR "/viewer_bookmarks.dat"
32 #define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */
33 #define MAX_COLUMNS 64 /* Max displayable string len (over-estimate) */
34 #define MAX_WIDTH 910 /* Max line length in WIDE mode */
35 #define READ_PREV_ZONE 910 /* Arbitrary number less than SMALL_BLOCK_SIZE */
36 #define SMALL_BLOCK_SIZE 0x1000 /* 4k: Smallest file chunk we will read */
37 #define LARGE_BLOCK_SIZE 0x2000 /* 8k: Preferable size of file chunk to read */
38 #define TOP_SECTOR buffer
39 #define MID_SECTOR (buffer + SMALL_BLOCK_SIZE)
40 #define BOTTOM_SECTOR (buffer + 2*(SMALL_BLOCK_SIZE))
41 #define SCROLLBAR_WIDTH 6
43 #define MAX_BOOKMARKED_FILES ((buffer_size/(signed)sizeof(struct bookmarked_file_info))-1)
45 /* Out-Of-Bounds test for any pointer to data in the buffer */
46 #define BUFFER_OOB(p) ((p) < buffer || (p) >= buffer_end)
48 /* Does the buffer contain the beginning of the file? */
49 #define BUFFER_BOF() (file_pos==0)
51 /* Does the buffer contain the end of the file? */
52 #define BUFFER_EOF() (file_size-file_pos <= buffer_size)
54 /* Formula for the endpoint address outside of buffer data */
55 #define BUFFER_END() \
56 ((BUFFER_EOF()) ? (file_size-file_pos+buffer) : (buffer+buffer_size))
58 /* Is the entire file being shown in one screen? */
59 #define ONE_SCREEN_FITS_ALL() \
60 (next_screen_ptr==NULL && screen_top_ptr==buffer && BUFFER_BOF())
62 /* Is a scrollbar called for on the current screen? */
63 #define NEED_SCROLLBAR() \
64 ((!(ONE_SCREEN_FITS_ALL())) && (prefs.scrollbar_mode==SB_ON))
66 /* variable button definitions */
69 #if CONFIG_KEYPAD == RECORDER_PAD
70 #define VIEWER_QUIT BUTTON_OFF
71 #define VIEWER_PAGE_UP BUTTON_UP
72 #define VIEWER_PAGE_DOWN BUTTON_DOWN
73 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
74 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
75 #define VIEWER_MENU BUTTON_F1
76 #define VIEWER_AUTOSCROLL BUTTON_PLAY
77 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
78 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
79 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
80 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
82 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
83 #define VIEWER_QUIT BUTTON_OFF
84 #define VIEWER_PAGE_UP BUTTON_UP
85 #define VIEWER_PAGE_DOWN BUTTON_DOWN
86 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
87 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
88 #define VIEWER_MENU BUTTON_F1
89 #define VIEWER_AUTOSCROLL BUTTON_SELECT
90 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
91 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
92 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
93 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
96 #elif CONFIG_KEYPAD == ONDIO_PAD
97 #define VIEWER_QUIT BUTTON_OFF
98 #define VIEWER_PAGE_UP BUTTON_UP
99 #define VIEWER_PAGE_DOWN BUTTON_DOWN
100 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
101 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
102 #define VIEWER_MENU (BUTTON_MENU|BUTTON_REPEAT)
103 #define VIEWER_AUTOSCROLL_PRE BUTTON_MENU
104 #define VIEWER_AUTOSCROLL (BUTTON_MENU|BUTTON_REL)
107 #elif CONFIG_KEYPAD == PLAYER_PAD
108 #define VIEWER_QUIT BUTTON_STOP
109 #define VIEWER_PAGE_UP BUTTON_LEFT
110 #define VIEWER_PAGE_DOWN BUTTON_RIGHT
111 #define VIEWER_SCREEN_LEFT (BUTTON_ON|BUTTON_LEFT)
112 #define VIEWER_SCREEN_RIGHT (BUTTON_ON|BUTTON_RIGHT)
113 #define VIEWER_MENU BUTTON_MENU
114 #define VIEWER_AUTOSCROLL BUTTON_PLAY
116 /* iRiver H1x0 && H3x0 keys */
117 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
118 (CONFIG_KEYPAD == IRIVER_H300_PAD)
119 #define VIEWER_QUIT BUTTON_OFF
120 #define VIEWER_PAGE_UP BUTTON_UP
121 #define VIEWER_PAGE_DOWN BUTTON_DOWN
122 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
123 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
124 #define VIEWER_MENU BUTTON_MODE
125 #define VIEWER_AUTOSCROLL BUTTON_SELECT
126 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
127 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
128 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
129 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
131 #define VIEWER_RC_QUIT BUTTON_RC_STOP
134 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
135 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
136 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
137 #define VIEWER_QUIT_PRE BUTTON_SELECT
138 #define VIEWER_QUIT (BUTTON_SELECT | BUTTON_MENU)
139 #define VIEWER_PAGE_UP BUTTON_SCROLL_BACK
140 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_FWD
141 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
142 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
143 #define VIEWER_MENU BUTTON_MENU
144 #define VIEWER_AUTOSCROLL BUTTON_PLAY
147 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
148 #define VIEWER_QUIT BUTTON_PLAY
149 #define VIEWER_PAGE_UP BUTTON_UP
150 #define VIEWER_PAGE_DOWN BUTTON_DOWN
151 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
152 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
153 #define VIEWER_MENU BUTTON_MODE
154 #define VIEWER_AUTOSCROLL BUTTON_SELECT
157 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
158 #define VIEWER_QUIT BUTTON_POWER
159 #define VIEWER_PAGE_UP BUTTON_UP
160 #define VIEWER_PAGE_DOWN BUTTON_DOWN
161 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
162 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
163 #define VIEWER_MENU BUTTON_SELECT
164 #define VIEWER_AUTOSCROLL BUTTON_PLAY
167 #elif CONFIG_KEYPAD == GIGABEAT_PAD
168 #define VIEWER_QUIT BUTTON_POWER
169 #define VIEWER_PAGE_UP BUTTON_UP
170 #define VIEWER_PAGE_DOWN BUTTON_DOWN
171 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
172 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
173 #define VIEWER_MENU BUTTON_MENU
174 #define VIEWER_AUTOSCROLL BUTTON_A
176 /* Sansa E200 keys */
177 #elif CONFIG_KEYPAD == SANSA_E200_PAD
178 #define VIEWER_QUIT BUTTON_POWER
179 #define VIEWER_PAGE_UP BUTTON_UP
180 #define VIEWER_PAGE_DOWN BUTTON_DOWN
181 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
182 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
183 #define VIEWER_MENU BUTTON_SELECT
184 #define VIEWER_AUTOSCROLL BUTTON_REC
185 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
186 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
188 /* Sansa C200 keys */
189 #elif CONFIG_KEYPAD == SANSA_C200_PAD
190 #define VIEWER_QUIT BUTTON_POWER
191 #define VIEWER_PAGE_UP BUTTON_VOL_UP
192 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
193 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
194 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
195 #define VIEWER_MENU BUTTON_SELECT
196 #define VIEWER_AUTOSCROLL BUTTON_REC
197 #define VIEWER_LINE_UP BUTTON_UP
198 #define VIEWER_LINE_DOWN BUTTON_DOWN
200 /* iriver H10 keys */
201 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
202 #define VIEWER_QUIT BUTTON_POWER
203 #define VIEWER_PAGE_UP BUTTON_SCROLL_UP
204 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_DOWN
205 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
206 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
207 #define VIEWER_MENU BUTTON_REW
208 #define VIEWER_AUTOSCROLL BUTTON_PLAY
211 #elif CONFIG_KEYPAD == MROBE500_PAD
212 #define VIEWER_QUIT BUTTON_POWER
213 #define VIEWER_PAGE_UP BUTTON_RC_PLAY
214 #define VIEWER_PAGE_DOWN BUTTON_RC_DOWN
215 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
216 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
217 #define VIEWER_MENU BUTTON_RC_HEART
218 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
221 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
222 #define VIEWER_QUIT BUTTON_BACK
223 #define VIEWER_PAGE_UP BUTTON_PREV
224 #define VIEWER_PAGE_DOWN BUTTON_NEXT
225 #define VIEWER_SCREEN_LEFT (BUTTON_PLAY | BUTTON_LEFT)
226 #define VIEWER_SCREEN_RIGHT (BUTTON_PLAY | BUTTON_RIGHT)
227 #define VIEWER_MENU BUTTON_MENU
228 #define VIEWER_AUTOSCROLL_PRE BUTTON_PLAY
229 #define VIEWER_AUTOSCROLL (BUTTON_PLAY|BUTTON_REL)
230 #define VIEWER_LINE_UP BUTTON_UP
231 #define VIEWER_LINE_DOWN BUTTON_DOWN
232 #define VIEWER_COLUMN_LEFT BUTTON_LEFT
233 #define VIEWER_COLUMN_RIGHT BUTTON_RIGHT
236 #elif CONFIG_KEYPAD == MROBE100_PAD
237 #define VIEWER_QUIT BUTTON_POWER
238 #define VIEWER_PAGE_UP BUTTON_UP
239 #define VIEWER_PAGE_DOWN BUTTON_DOWN
240 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
241 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
242 #define VIEWER_MENU BUTTON_MENU
243 #define VIEWER_AUTOSCROLL BUTTON_DISPLAY
246 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
247 #define VIEWER_QUIT BUTTON_RC_REC
248 #define VIEWER_PAGE_UP BUTTON_RC_VOL_UP
249 #define VIEWER_PAGE_DOWN BUTTON_RC_VOL_DOWN
250 #define VIEWER_SCREEN_LEFT BUTTON_RC_REW
251 #define VIEWER_SCREEN_RIGHT BUTTON_RC_FF
252 #define VIEWER_MENU BUTTON_RC_MENU
253 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
254 #define VIEWER_RC_QUIT BUTTON_REC
257 #elif CONFIG_KEYPAD == COWOND2_PAD
258 #define VIEWER_QUIT BUTTON_POWER
259 #define VIEWER_MENU BUTTON_MENU
261 #elif CONFIG_KEYPAD == IAUDIO67_PAD
262 #define VIEWER_QUIT BUTTON_POWER
263 #define VIEWER_PAGE_UP BUTTON_VOLUP
264 #define VIEWER_PAGE_DOWN BUTTON_VOLDOWN
265 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
266 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
267 #define VIEWER_MENU BUTTON_MENU
268 #define VIEWER_AUTOSCROLL BUTTON_PLAY
269 #define VIEWER_RC_QUIT BUTTON_STOP
272 #error No keymap defined!
275 #ifdef HAVE_TOUCHSCREEN
277 #define VIEWER_QUIT BUTTON_TOPLEFT
279 #ifndef VIEWER_PAGE_UP
280 #define VIEWER_PAGE_UP BUTTON_TOPMIDDLE
282 #ifndef VIEWER_PAGE_DOWN
283 #define VIEWER_PAGE_DOWN BUTTON_BOTTOMMIDDLE
285 #ifndef VIEWER_SCREEN_LEFT
286 #define VIEWER_SCREEN_LEFT BUTTON_MIDLEFT
288 #ifndef VIEWER_SCREEN_RIGHT
289 #define VIEWER_SCREEN_RIGHT BUTTON_MIDRIGHT
292 #define VIEWER_MENU BUTTON_TOPRIGHT
294 #ifndef VIEWER_AUTOSCROLL
295 #define VIEWER_AUTOSCROLL BUTTON_CENTER
299 /* stuff for the bookmarking */
300 struct bookmarked_file_info
{
303 char filename
[MAX_PATH
];
306 struct bookmark_file_data
{
307 signed int bookmarked_files_count
;
308 struct bookmarked_file_info bookmarks
[];
321 REFLOW
, /* won't be set on charcell LCD, must be last */
345 } encoding
; /* FIXME: What should default encoding be? */
347 #ifdef HAVE_LCD_BITMAP
358 #endif /* HAVE_LCD_BITMAP */
365 int autoscroll_speed
;
369 struct preferences prefs
;
370 struct preferences old_prefs
;
372 static unsigned char *buffer
;
373 static long buffer_size
;
374 static unsigned char line_break
[] = {0,0x20,9,0xB,0xC,'-'};
375 static int display_columns
; /* number of (pixel) columns on the display */
376 static int display_lines
; /* number of lines on the display */
377 static int draw_columns
; /* number of (pixel) columns available for text */
378 static int par_indent_spaces
; /* number of spaces to indent first paragraph */
380 static const char *file_name
;
381 static long file_size
;
382 static long start_position
; /* position in the file after the viewer is started */
383 static bool mac_text
;
384 static long file_pos
; /* Position of the top of the buffer in the file */
385 static unsigned char *buffer_end
; /*Set to BUFFER_END() when file_pos changes*/
386 static int max_line_len
;
387 static unsigned char *screen_top_ptr
;
388 static unsigned char *next_screen_ptr
;
389 static unsigned char *next_screen_to_draw_ptr
;
390 static unsigned char *next_line_ptr
;
391 static const struct plugin_api
* rb
;
392 #ifdef HAVE_LCD_BITMAP
393 static struct font
*pf
;
397 int glyph_width(int ch
)
402 #ifdef HAVE_LCD_BITMAP
403 return rb
->font_get_width(pf
, ch
);
409 unsigned char* get_ucs(const unsigned char* str
, unsigned short* ch
)
411 unsigned char utf8_tmp
[6];
414 if (prefs
.encoding
== UTF8
)
415 return (unsigned char*)rb
->utf8decode(str
, ch
);
417 count
= BUFFER_OOB(str
+2)? 1:2;
418 rb
->iso_decode(str
, utf8_tmp
, prefs
.encoding
, count
);
419 rb
->utf8decode(utf8_tmp
, ch
);
421 if ((prefs
.encoding
== SJIS
&& *str
> 0xA0 && *str
< 0xE0) || prefs
.encoding
< SJIS
)
422 return (unsigned char*)str
+1;
424 return (unsigned char*)str
+2;
430 #define ADVANCE_COUNTERS(c) { width += glyph_width(c); k++; }
431 #define LINE_IS_FULL ((k>=MAX_COLUMNS-1) ||( width >= draw_columns))
432 #define LINE_IS_NOT_FULL ((k<MAX_COLUMNS-1) &&( width < draw_columns))
433 static unsigned char* crop_at_width(const unsigned char* p
)
437 const unsigned char *oldp
= p
;
441 while (LINE_IS_NOT_FULL
) {
444 ADVANCE_COUNTERS(ch
);
447 return (unsigned char*)oldp
;
450 static unsigned char* find_first_feed(const unsigned char* p
, int size
)
454 for (i
=0; i
< size
; i
++)
456 return (unsigned char*) p
+i
;
461 static unsigned char* find_last_feed(const unsigned char* p
, int size
)
465 for (i
=size
-1; i
>=0; i
--)
467 return (unsigned char*) p
+i
;
472 static unsigned char* find_last_space(const unsigned char* p
, int size
)
476 k
= (prefs
.line_mode
==JOIN
) || (prefs
.line_mode
==REFLOW
) ? 0:1;
478 if (!BUFFER_OOB(&p
[size
]))
479 for (j
=k
; j
< ((int) sizeof(line_break
)) - 1; j
++)
480 if (p
[size
] == line_break
[j
])
481 return (unsigned char*) p
+size
;
483 for (i
=size
-1; i
>=0; i
--)
484 for (j
=k
; j
< (int) sizeof(line_break
); j
++)
486 if (!((p
[i
] == '-') && (prefs
.word_mode
== WRAP
)))
487 if (p
[i
] == line_break
[j
])
488 return (unsigned char*) p
+i
;
494 static unsigned char* find_next_line(const unsigned char* cur_line
, bool *is_short
)
496 const unsigned char *next_line
= NULL
;
497 int size
, i
, j
, k
, width
, search_len
, spaces
, newlines
;
501 if (is_short
!= NULL
)
504 if BUFFER_OOB(cur_line
)
507 if (prefs
.view_mode
== WIDE
) {
508 search_len
= MAX_WIDTH
;
510 else { /* prefs.view_mode == NARROW */
511 search_len
= crop_at_width(cur_line
) - cur_line
;
514 size
= BUFFER_OOB(cur_line
+search_len
) ? buffer_end
-cur_line
: search_len
;
516 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
)) {
517 /* Need to scan ahead and possibly increase search_len and size,
518 or possibly set next_line at second hard return in a row. */
521 for (j
=k
=width
=spaces
=newlines
=0; ; j
++) {
522 if (BUFFER_OOB(cur_line
+j
))
525 size
= search_len
= j
;
532 if (prefs
.line_mode
== REFLOW
) {
535 next_line
= cur_line
+ size
;
536 return (unsigned char*) next_line
;
538 if (j
==0) /* i=1 is intentional */
539 for (i
=0; i
<par_indent_spaces
; i
++)
540 ADVANCE_COUNTERS(' ');
542 if (!first_chars
) spaces
++;
548 next_line
= cur_line
+ size
- spaces
;
549 if (next_line
!= cur_line
)
550 return (unsigned char*) next_line
;
556 if (BUFFER_OOB(cur_line
+size
) || size
> 2*search_len
)
559 spaces
= first_chars
? 0:1;
563 if (prefs
.line_mode
==JOIN
|| newlines
>0) {
566 ADVANCE_COUNTERS(' ');
568 size
= search_len
= j
;
574 /* REFLOW, multiple spaces between words: count only
575 * one. If more are needed, they will be added
579 ADVANCE_COUNTERS(' ');
581 size
= search_len
= j
;
592 /* find first hard return */
593 next_line
= find_first_feed(cur_line
, size
);
596 if (next_line
== NULL
)
597 if (size
== search_len
) {
598 if (prefs
.word_mode
== WRAP
) /* Find last space */
599 next_line
= find_last_space(cur_line
, size
);
601 if (next_line
== NULL
)
602 next_line
= crop_at_width(cur_line
);
604 if (prefs
.word_mode
== WRAP
)
606 i
<WRAP_TRIM
&& isspace(next_line
[0]) && !BUFFER_OOB(next_line
);
611 if (prefs
.line_mode
== EXPAND
)
612 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
613 if (next_line
[0] == 0)
614 if (next_line
!= cur_line
)
615 return (unsigned char*) next_line
;
617 /* If next_line is pointing to a zero, increment it; i.e.,
618 leave the terminator at the end of cur_line. If pointing
619 to a hyphen, increment only if there is room to display
620 the hyphen on current line (won't apply in WIDE mode,
621 since it's guarenteed there won't be room). */
622 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
623 if (next_line
[0] == 0)/* ||
624 (next_line[0] == '-' && next_line-cur_line < draw_columns)) */
627 if (BUFFER_OOB(next_line
))
633 return (unsigned char*) next_line
;
636 static unsigned char* find_prev_line(const unsigned char* cur_line
)
638 const unsigned char *prev_line
= NULL
;
639 const unsigned char *p
;
641 if BUFFER_OOB(cur_line
)
644 /* To wrap consistently at the same places, we must
645 start with a known hard return, then work downwards.
646 We can either search backwards for a hard return,
647 or simply start wrapping downwards from top of buffer.
648 If current line is not near top of buffer, this is
649 a file with long lines (paragraphs). We would need to
650 read earlier sectors before we could decide how to
651 properly wrap the lines above the current line, but
652 it probably is not worth the disk access. Instead,
653 start with top of buffer and wrap down from there.
654 This may result in some lines wrapping at different
655 points from where they wrap when scrolling down.
656 If buffer is at top of file, start at top of buffer. */
658 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
))
659 prev_line
= p
= NULL
;
661 prev_line
= p
= find_last_feed(buffer
, cur_line
-buffer
-1);
662 /* Null means no line feeds in buffer above current line. */
664 if (prev_line
== NULL
)
665 if (BUFFER_BOF() || cur_line
- buffer
> READ_PREV_ZONE
)
666 prev_line
= p
= buffer
;
667 /* (else return NULL and read previous block) */
669 /* Wrap downwards until too far, then use the one before. */
670 while (p
< cur_line
&& p
!= NULL
) {
672 p
= find_next_line(prev_line
, NULL
);
675 if (BUFFER_OOB(prev_line
))
678 return (unsigned char*) prev_line
;
681 static void fill_buffer(long pos
, unsigned char* buf
, unsigned size
)
683 /* Read from file and preprocess the data */
684 /* To minimize disk access, always read on sector boundaries */
686 bool found_CR
= false;
688 rb
->lseek(fd
, pos
, SEEK_SET
);
689 numread
= rb
->read(fd
, buf
, size
);
690 rb
->button_clear_queue(); /* clear button queue */
692 for(i
= 0; i
< numread
; i
++) {
709 case 0: /* No break between case 0 and default, intentionally */
722 static int read_and_synch(int direction
)
724 /* Read next (or prev) block, and reposition global pointers. */
725 /* direction: 1 for down (i.e., further into file), -1 for up */
726 int move_size
, move_vector
, offset
;
727 unsigned char *fill_buf
;
729 if (direction
== -1) /* up */ {
730 move_size
= SMALL_BLOCK_SIZE
;
732 fill_buf
= TOP_SECTOR
;
733 rb
->memcpy(BOTTOM_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
734 rb
->memcpy(MID_SECTOR
, TOP_SECTOR
, SMALL_BLOCK_SIZE
);
737 if (prefs
.view_mode
== WIDE
) {
738 /* WIDE mode needs more buffer so we have to read smaller blocks */
739 move_size
= SMALL_BLOCK_SIZE
;
740 offset
= LARGE_BLOCK_SIZE
;
741 fill_buf
= BOTTOM_SECTOR
;
742 rb
->memcpy(TOP_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
743 rb
->memcpy(MID_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
746 move_size
= LARGE_BLOCK_SIZE
;
747 offset
= SMALL_BLOCK_SIZE
;
748 fill_buf
= MID_SECTOR
;
749 rb
->memcpy(TOP_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
752 move_vector
= direction
* move_size
;
753 screen_top_ptr
-= move_vector
;
754 file_pos
+= move_vector
;
755 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
756 fill_buffer(file_pos
+ offset
, fill_buf
, move_size
);
760 static void viewer_scroll_up(void)
764 p
= find_prev_line(screen_top_ptr
);
765 if (p
== NULL
&& !BUFFER_BOF()) {
767 p
= find_prev_line(screen_top_ptr
);
773 static void viewer_scroll_down(void)
775 if (next_screen_ptr
!= NULL
)
776 screen_top_ptr
= next_line_ptr
;
779 #ifdef HAVE_LCD_BITMAP
780 static void viewer_scrollbar(void) {
781 int items
, min_shown
, max_shown
;
783 items
= (int) file_size
; /* (SH1 int is same as long) */
784 min_shown
= (int) file_pos
+ (screen_top_ptr
- buffer
);
786 if (next_screen_ptr
== NULL
)
789 max_shown
= min_shown
+ (next_screen_ptr
- screen_top_ptr
);
791 rb
->gui_scrollbar_draw(rb
->screens
[SCREEN_MAIN
],0, 0, SCROLLBAR_WIDTH
-1,
792 LCD_HEIGHT
, items
, min_shown
, max_shown
, VERTICAL
);
796 static void viewer_draw(int col
)
798 int i
, j
, k
, line_len
, line_width
, resynch_move
, spaces
, left_col
=0;
799 int width
, extra_spaces
, indent_spaces
, spaces_per_word
;
800 bool multiple_spacing
, line_is_short
;
802 unsigned char *str
, *oldstr
;
803 unsigned char *line_begin
;
804 unsigned char *line_end
;
806 unsigned char scratch_buffer
[MAX_COLUMNS
+ 1];
807 unsigned char utf8_buffer
[MAX_COLUMNS
*4 + 1];
808 unsigned char *endptr
;
810 /* If col==-1 do all calculations but don't display */
812 #ifdef HAVE_LCD_BITMAP
813 left_col
= prefs
.need_scrollbar
? SCROLLBAR_WIDTH
:0;
817 rb
->lcd_clear_display();
820 line_begin
= line_end
= screen_top_ptr
;
822 for (i
= 0; i
< display_lines
; i
++) {
823 if (BUFFER_OOB(line_end
))
824 break; /* Happens after display last line at BUFFER_EOF() */
826 line_begin
= line_end
;
827 line_end
= find_next_line(line_begin
, &line_is_short
);
829 if (line_end
== NULL
) {
831 if (i
< display_lines
- 1 && !BUFFER_BOF()) {
833 rb
->lcd_clear_display();
835 for (; i
< display_lines
- 1; i
++)
838 line_begin
= line_end
= screen_top_ptr
;
843 line_end
= buffer_end
;
847 resynch_move
= read_and_synch(1); /* Read block & move ptrs */
848 line_begin
-= resynch_move
;
850 next_line_ptr
-= resynch_move
;
852 line_end
= find_next_line(line_begin
, NULL
);
853 if (line_end
== NULL
) /* Should not really happen */
857 line_len
= line_end
- line_begin
;
859 /* calculate line_len */
860 str
= oldstr
= line_begin
;
862 while (str
< line_end
) {
864 str
= crop_at_width(str
);
867 line_width
= j
*draw_columns
;
868 while (oldstr
< line_end
) {
869 oldstr
= get_ucs(oldstr
, &ch
);
870 line_width
+= glyph_width(ch
);
873 if (prefs
.line_mode
== JOIN
) {
874 if (line_begin
[0] == 0) {
876 if (prefs
.word_mode
== CHOP
)
881 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
882 if (k
== MAX_COLUMNS
)
892 scratch_buffer
[k
++] = ' ';
897 scratch_buffer
[k
++] = ' ';
898 if (k
== MAX_COLUMNS
- 1)
901 scratch_buffer
[k
++] = c
;
906 scratch_buffer
[k
] = 0;
907 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
908 prefs
.encoding
, draw_columns
/glyph_width('i'));
912 else if (prefs
.line_mode
== REFLOW
) {
913 if (line_begin
[0] == 0) {
915 if (prefs
.word_mode
== CHOP
)
922 if (!line_is_short
) {
923 multiple_spacing
= false;
925 for (str
= line_begin
; str
< line_end
; ) {
926 str
= get_ucs(str
, &ch
);
930 if ((str
== line_begin
) && (prefs
.word_mode
==WRAP
))
931 /* special case: indent the paragraph,
932 * don't count spaces */
933 indent_spaces
= par_indent_spaces
;
934 else if (!multiple_spacing
)
936 multiple_spacing
= true;
939 multiple_spacing
= false;
940 width
+= glyph_width(ch
);
944 if (multiple_spacing
) spaces
--;
947 /* total number of spaces to insert between words */
948 extra_spaces
= (draw_columns
-width
)/glyph_width(' ')
950 /* number of spaces between each word*/
951 spaces_per_word
= extra_spaces
/ spaces
;
952 /* number of words with n+1 spaces (to fill up) */
953 extra_spaces
= extra_spaces
% spaces
;
954 if (spaces_per_word
> 2) { /* too much spacing is awful */
958 } else { /* this doesn't matter much... no spaces anyway */
959 spaces_per_word
= extra_spaces
= 0;
961 } else { /* end of a paragraph: don't fill line */
966 multiple_spacing
= false;
967 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
968 if (k
== MAX_COLUMNS
)
975 if (j
==0 && prefs
.word_mode
==WRAP
) { /* indent paragraph */
976 for (j
=0; j
<par_indent_spaces
; j
++)
977 scratch_buffer
[k
++] = ' ';
980 else if (!multiple_spacing
) {
981 for (width
= spaces
<extra_spaces
? -1:0; width
< spaces_per_word
; width
++)
982 scratch_buffer
[k
++] = ' ';
985 multiple_spacing
= true;
988 scratch_buffer
[k
++] = c
;
989 multiple_spacing
= false;
995 scratch_buffer
[k
] = 0;
996 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
997 prefs
.encoding
, k
-col
);
1001 else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */
1003 if (line_width
> col
) {
1004 str
= oldstr
= line_begin
;
1007 while( (width
<draw_columns
) && (oldstr
<line_end
) )
1009 oldstr
= get_ucs(oldstr
, &ch
);
1011 k
-= glyph_width(ch
);
1012 line_begin
= oldstr
;
1014 width
+= glyph_width(ch
);
1018 if(prefs
.view_mode
==WIDE
)
1019 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1020 prefs
.encoding
, oldstr
-line_begin
);
1022 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1023 prefs
.encoding
, line_end
-line_begin
);
1027 if (col
!= -1 && line_width
> col
)
1028 #ifdef HAVE_LCD_BITMAP
1029 rb
->lcd_putsxy(left_col
, i
*pf
->height
, utf8_buffer
);
1031 rb
->lcd_puts(left_col
, i
, utf8_buffer
);
1033 if (line_width
> max_line_len
)
1034 max_line_len
= line_width
;
1037 next_line_ptr
= line_end
;
1039 next_screen_ptr
= line_end
;
1040 if (BUFFER_OOB(next_screen_ptr
))
1041 next_screen_ptr
= NULL
;
1043 #ifdef HAVE_LCD_BITMAP
1044 next_screen_to_draw_ptr
= prefs
.page_mode
==OVERLAP
? line_begin
: next_screen_ptr
;
1046 if (prefs
.need_scrollbar
)
1049 next_screen_to_draw_ptr
= next_screen_ptr
;
1056 static void viewer_top(void)
1058 /* Read top of file into buffer
1059 and point screen pointer to top */
1063 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1064 fill_buffer(0, buffer
, buffer_size
);
1067 screen_top_ptr
= buffer
;
1070 static void viewer_bottom(void)
1072 /* Read bottom of file into buffer
1073 and point screen pointer to bottom */
1076 if (file_size
> buffer_size
) {
1077 /* Find last buffer in file, round up to next sector boundary */
1078 last_sectors
= file_size
- buffer_size
+ SMALL_BLOCK_SIZE
;
1079 last_sectors
/= SMALL_BLOCK_SIZE
;
1080 last_sectors
*= SMALL_BLOCK_SIZE
;
1086 if (file_pos
!= last_sectors
)
1088 file_pos
= last_sectors
;
1089 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1090 fill_buffer(last_sectors
, buffer
, buffer_size
);
1093 screen_top_ptr
= buffer_end
-1;
1096 #ifdef HAVE_LCD_BITMAP
1097 static void init_need_scrollbar(void) {
1098 /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
1099 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
1101 prefs
.need_scrollbar
= NEED_SCROLLBAR();
1102 draw_columns
= prefs
.need_scrollbar
? display_columns
-SCROLLBAR_WIDTH
: display_columns
;
1103 par_indent_spaces
= draw_columns
/(5*glyph_width(' '));
1106 #define init_need_scrollbar()
1109 static bool viewer_init(void)
1111 #ifdef HAVE_LCD_BITMAP
1113 pf
= rb
->font_get(FONT_UI
);
1115 display_lines
= LCD_HEIGHT
/ pf
->height
;
1116 draw_columns
= display_columns
= LCD_WIDTH
;
1118 /* REAL fixed pitch :) all chars use up 1 cell */
1120 draw_columns
= display_columns
= 11;
1121 par_indent_spaces
= 2;
1124 fd
= rb
->open(file_name
, O_RDONLY
);
1128 file_size
= rb
->filesize(fd
);
1132 /* Init mac_text value used in processing buffer */
1138 static void viewer_default_settings(void)
1140 prefs
.word_mode
= WRAP
;
1141 prefs
.line_mode
= NORMAL
;
1142 prefs
.view_mode
= NARROW
;
1143 prefs
.scroll_mode
= PAGE
;
1144 #ifdef HAVE_LCD_BITMAP
1145 prefs
.page_mode
= NO_OVERLAP
;
1146 prefs
.scrollbar_mode
= SB_OFF
;
1148 prefs
.autoscroll_speed
= 1;
1149 /* Set codepage to system default */
1150 prefs
.encoding
= rb
->global_settings
->default_codepage
;
1153 static void viewer_load_settings(void) /* same name as global, but not the same file.. */
1156 struct bookmark_file_data
*data
;
1157 struct bookmarked_file_info this_bookmark
;
1159 /* read settings file */
1160 settings_fd
=rb
->open(SETTINGS_FILE
, O_RDONLY
);
1161 if ((settings_fd
>= 0) && (rb
->filesize(settings_fd
) == sizeof(struct preferences
)))
1163 rb
->read(settings_fd
, &prefs
, sizeof(struct preferences
));
1164 rb
->close(settings_fd
);
1168 /* load default settings if there is no settings file */
1169 viewer_default_settings();
1172 rb
->memcpy(&old_prefs
, &prefs
, sizeof(struct preferences
));
1174 data
= (struct bookmark_file_data
*)buffer
; /* grab the text buffer */
1175 data
->bookmarked_files_count
= 0;
1177 /* read bookmarks if file exists */
1178 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_RDONLY
);
1179 if (settings_fd
>= 0)
1181 /* figure out how many items to read */
1182 rb
->read(settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1183 if (data
->bookmarked_files_count
> MAX_BOOKMARKED_FILES
)
1184 data
->bookmarked_files_count
= MAX_BOOKMARKED_FILES
;
1185 rb
->read(settings_fd
, data
->bookmarks
,
1186 sizeof(struct bookmarked_file_info
) * data
->bookmarked_files_count
);
1187 rb
->close(settings_fd
);
1191 screen_top_ptr
= buffer
;
1193 /* check if current file is in list */
1194 for (i
=0; i
< data
->bookmarked_files_count
; i
++)
1196 if (!rb
->strcmp(file_name
, data
->bookmarks
[i
].filename
))
1198 int screen_pos
= data
->bookmarks
[i
].file_position
+ data
->bookmarks
[i
].top_ptr_pos
;
1199 int screen_top
= screen_pos
% buffer_size
;
1200 file_pos
= screen_pos
- screen_top
;
1201 screen_top_ptr
= buffer
+ screen_top
;
1206 this_bookmark
.file_position
= file_pos
;
1207 this_bookmark
.top_ptr_pos
= screen_top_ptr
- buffer
;
1209 rb
->memset(&this_bookmark
.filename
[0],0,MAX_PATH
);
1210 rb
->strcpy(this_bookmark
.filename
,file_name
);
1212 /* prevent potential slot overflow */
1213 if (i
>= data
->bookmarked_files_count
)
1215 if (i
< MAX_BOOKMARKED_FILES
)
1216 data
->bookmarked_files_count
++;
1218 i
= MAX_BOOKMARKED_FILES
-1;
1221 /* write bookmark file with spare slot in first position
1222 to be filled in by viewer_save_settings */
1223 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1224 if (settings_fd
>=0 )
1227 rb
->write (settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1229 /* write the current bookmark */
1230 rb
->write (settings_fd
, &this_bookmark
, sizeof(struct bookmarked_file_info
));
1232 /* write everything that was before this bookmark */
1233 rb
->write (settings_fd
, data
->bookmarks
, sizeof(struct bookmarked_file_info
)*i
);
1235 rb
->close(settings_fd
);
1238 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1240 if (BUFFER_OOB(screen_top_ptr
))
1242 screen_top_ptr
= buffer
;
1245 fill_buffer(file_pos
, buffer
, buffer_size
);
1247 /* remember the current position */
1248 start_position
= file_pos
+ screen_top_ptr
- buffer
;
1250 init_need_scrollbar();
1253 static void viewer_save_settings(void)/* same name as global, but not the same file.. */
1257 /* save the viewer settings if they have been changed */
1258 if (rb
->memcmp(&prefs
, &old_prefs
, sizeof(struct preferences
)))
1260 settings_fd
= rb
->creat(SETTINGS_FILE
); /* create the settings file */
1262 if (settings_fd
>= 0 )
1264 rb
->write (settings_fd
, &prefs
, sizeof(struct preferences
));
1265 rb
->close(settings_fd
);
1269 /* save the bookmark if the position has changed */
1270 if (file_pos
+ screen_top_ptr
- buffer
!= start_position
)
1272 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1274 if (settings_fd
>= 0 )
1276 struct bookmarked_file_info b
;
1277 b
.file_position
= file_pos
+ screen_top_ptr
- buffer
;
1278 b
.top_ptr_pos
= 0; /* this is only kept for legassy reasons */
1279 rb
->memset(&b
.filename
[0],0,MAX_PATH
);
1280 rb
->strcpy(b
.filename
,file_name
);
1281 rb
->PREFIX(lseek
)(settings_fd
,sizeof(signed int),SEEK_SET
);
1282 rb
->write (settings_fd
, &b
, sizeof(struct bookmarked_file_info
));
1283 rb
->close(settings_fd
);
1288 static void viewer_exit(void *parameter
)
1292 viewer_save_settings();
1296 static int col_limit(int col
)
1301 if (col
> max_line_len
- 2*glyph_width('o'))
1302 col
= max_line_len
- 2*glyph_width('o');
1307 /* settings helper functions */
1309 static bool encoding_setting(void)
1311 static const struct opt_items names
[] = {
1316 {"ISO-8859-11", -1},
1328 return rb
->set_option("Encoding", &prefs
.encoding
, INT
, names
,
1329 sizeof(names
) / sizeof(names
[0]), NULL
);
1332 static bool word_wrap_setting(void)
1334 static const struct opt_items names
[] = {
1336 {"Off (Chop Words)", -1},
1339 return rb
->set_option("Word Wrap", &prefs
.word_mode
, INT
,
1343 static bool line_mode_setting(void)
1345 static const struct opt_items names
[] = {
1348 {"Expand Lines", -1},
1349 #ifdef HAVE_LCD_BITMAP
1350 {"Reflow Lines", -1},
1354 return rb
->set_option("Line Mode", &prefs
.line_mode
, INT
, names
,
1355 sizeof(names
) / sizeof(names
[0]), NULL
);
1358 static bool view_mode_setting(void)
1360 static const struct opt_items names
[] = {
1361 {"No (Narrow)", -1},
1365 ret
= rb
->set_option("Wide View", &prefs
.view_mode
, INT
,
1367 if (prefs
.view_mode
== NARROW
)
1372 static bool scroll_mode_setting(void)
1374 static const struct opt_items names
[] = {
1375 {"Scroll by Page", -1},
1376 {"Scroll by Line", -1},
1379 return rb
->set_option("Scroll Mode", &prefs
.scroll_mode
, INT
,
1383 #ifdef HAVE_LCD_BITMAP
1384 static bool page_mode_setting(void)
1386 static const struct opt_items names
[] = {
1391 return rb
->set_option("Overlap Pages", &prefs
.page_mode
, INT
,
1395 static bool scrollbar_setting(void)
1397 static const struct opt_items names
[] = {
1402 return rb
->set_option("Show Scrollbar", &prefs
.scrollbar_mode
, INT
,
1407 static bool autoscroll_speed_setting(void)
1409 return rb
->set_int("Auto-scroll Speed", "", UNIT_INT
,
1410 &prefs
.autoscroll_speed
, NULL
, 1, 1, 10, NULL
);
1413 static bool viewer_options_menu(void)
1418 static const struct menu_item items
[] = {
1419 {"Encoding", encoding_setting
},
1420 {"Word Wrap", word_wrap_setting
},
1421 {"Line Mode", line_mode_setting
},
1422 {"Wide View", view_mode_setting
},
1423 #ifdef HAVE_LCD_BITMAP
1424 {"Show Scrollbar", scrollbar_setting
},
1425 {"Overlap Pages", page_mode_setting
},
1427 {"Scroll Mode", scroll_mode_setting
},
1428 {"Auto-Scroll Speed", autoscroll_speed_setting
},
1430 m
= menu_init(rb
, items
, sizeof(items
) / sizeof(*items
),
1431 NULL
, NULL
, NULL
, NULL
);
1433 result
= menu_run(m
);
1435 #ifdef HAVE_LCD_BITMAP
1437 /* Show-scrollbar mode for current view-width mode */
1438 init_need_scrollbar();
1443 static void viewer_menu(void)
1447 static const struct menu_item items
[] = {
1449 {"Viewer Options", NULL
},
1450 {"Show Playback Menu", NULL
},
1454 m
= menu_init(rb
, items
, sizeof(items
) / sizeof(*items
), NULL
, NULL
, NULL
, NULL
);
1455 result
=menu_show(m
);
1463 case 1: /* change settings */
1464 done
= viewer_options_menu();
1466 case 2: /* playback control */
1467 playback_control(rb
, NULL
);
1469 case 3: /* return */
1476 enum plugin_status
plugin_start(const struct plugin_api
* api
, const void* file
)
1479 int lastbutton
= BUTTON_NONE
;
1480 bool autoscroll
= false;
1484 old_tick
= *rb
->current_tick
;
1486 /* get the plugin buffer */
1487 buffer
= rb
->plugin_get_buffer((size_t *)&buffer_size
);
1490 return PLUGIN_ERROR
;
1495 rb
->splash(HZ
, "Error opening file.");
1496 return PLUGIN_ERROR
;
1499 viewer_load_settings(); /* load the preferences and bookmark */
1502 rb
->lcd_set_backdrop(NULL
);
1511 if(old_tick
<= *rb
->current_tick
- (110-prefs
.autoscroll_speed
*10))
1513 viewer_scroll_down();
1515 old_tick
= *rb
->current_tick
;
1519 button
= rb
->button_get_w_tmo(HZ
/10);
1525 case VIEWER_AUTOSCROLL
:
1526 #ifdef VIEWER_AUTOSCROLL_PRE
1527 if (lastbutton
!= VIEWER_AUTOSCROLL_PRE
)
1530 autoscroll
= !autoscroll
;
1533 case VIEWER_PAGE_UP
:
1534 case VIEWER_PAGE_UP
| BUTTON_REPEAT
:
1535 if (prefs
.scroll_mode
== PAGE
)
1538 #ifdef HAVE_LCD_BITMAP
1539 for (i
= prefs
.page_mode
==OVERLAP
? 1:0; i
< display_lines
; i
++)
1541 for (i
= 0; i
< display_lines
; i
++)
1547 old_tick
= *rb
->current_tick
;
1551 case VIEWER_PAGE_DOWN
:
1552 case VIEWER_PAGE_DOWN
| BUTTON_REPEAT
:
1553 if (prefs
.scroll_mode
== PAGE
)
1556 if (next_screen_ptr
!= NULL
)
1557 screen_top_ptr
= next_screen_to_draw_ptr
;
1560 viewer_scroll_down();
1561 old_tick
= *rb
->current_tick
;
1565 case VIEWER_SCREEN_LEFT
:
1566 case VIEWER_SCREEN_LEFT
| BUTTON_REPEAT
:
1567 if (prefs
.view_mode
== WIDE
) {
1569 col
-= draw_columns
;
1570 col
= col_limit(col
);
1572 else { /* prefs.view_mode == NARROW */
1580 case VIEWER_SCREEN_RIGHT
:
1581 case VIEWER_SCREEN_RIGHT
| BUTTON_REPEAT
:
1582 if (prefs
.view_mode
== WIDE
) {
1584 col
+= draw_columns
;
1585 col
= col_limit(col
);
1587 else { /* prefs.view_mode == NARROW */
1588 /* Bottom of file */
1595 #ifdef VIEWER_LINE_UP
1596 case VIEWER_LINE_UP
:
1597 case VIEWER_LINE_UP
| BUTTON_REPEAT
:
1598 /* Scroll up one line */
1600 old_tick
= *rb
->current_tick
;
1604 case VIEWER_LINE_DOWN
:
1605 case VIEWER_LINE_DOWN
| BUTTON_REPEAT
:
1606 /* Scroll down one line */
1607 if (next_screen_ptr
!= NULL
)
1608 screen_top_ptr
= next_line_ptr
;
1609 old_tick
= *rb
->current_tick
;
1613 #ifdef VIEWER_COLUMN_LEFT
1614 case VIEWER_COLUMN_LEFT
:
1615 case VIEWER_COLUMN_LEFT
| BUTTON_REPEAT
:
1616 if (prefs
.view_mode
== WIDE
) {
1617 /* Scroll left one column */
1618 col
-= glyph_width('o');
1619 col
= col_limit(col
);
1624 case VIEWER_COLUMN_RIGHT
:
1625 case VIEWER_COLUMN_RIGHT
| BUTTON_REPEAT
:
1626 if (prefs
.view_mode
== WIDE
) {
1627 /* Scroll right one column */
1628 col
+= glyph_width('o');
1629 col
= col_limit(col
);
1635 #ifdef VIEWER_RC_QUIT
1636 case VIEWER_RC_QUIT
:
1644 if (rb
->default_event_handler_ex(button
, viewer_exit
, NULL
)
1645 == SYS_USB_CONNECTED
)
1646 return PLUGIN_USB_CONNECTED
;
1649 if (button
!= BUTTON_NONE
)
1651 lastbutton
= button
;