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"
28 #define SETTINGS_FILE VIEWERS_DIR "/viewer.dat" /* binary file, so dont use .cfg */
29 #define BOOKMARKS_FILE VIEWERS_DIR "/viewer_bookmarks.dat"
31 #define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */
32 #define MAX_COLUMNS 64 /* Max displayable string len (over-estimate) */
33 #define MAX_WIDTH 910 /* Max line length in WIDE mode */
34 #define READ_PREV_ZONE 910 /* Arbitrary number less than SMALL_BLOCK_SIZE */
35 #define SMALL_BLOCK_SIZE 0x1000 /* 4k: Smallest file chunk we will read */
36 #define LARGE_BLOCK_SIZE 0x2000 /* 8k: Preferable size of file chunk to read */
37 #define TOP_SECTOR buffer
38 #define MID_SECTOR (buffer + SMALL_BLOCK_SIZE)
39 #define BOTTOM_SECTOR (buffer + 2*(SMALL_BLOCK_SIZE))
40 #define SCROLLBAR_WIDTH 6
42 #define MAX_BOOKMARKED_FILES ((buffer_size/(signed)sizeof(struct bookmarked_file_info))-1)
44 /* Out-Of-Bounds test for any pointer to data in the buffer */
45 #define BUFFER_OOB(p) ((p) < buffer || (p) >= buffer_end)
47 /* Does the buffer contain the beginning of the file? */
48 #define BUFFER_BOF() (file_pos==0)
50 /* Does the buffer contain the end of the file? */
51 #define BUFFER_EOF() (file_size-file_pos <= buffer_size)
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))
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())
61 /* Is a scrollbar called for on the current screen? */
62 #define NEED_SCROLLBAR() \
63 ((!(ONE_SCREEN_FITS_ALL())) && (prefs.scrollbar_mode==SB_ON))
65 /* variable button definitions */
68 #if CONFIG_KEYPAD == RECORDER_PAD
69 #define VIEWER_QUIT BUTTON_OFF
70 #define VIEWER_PAGE_UP BUTTON_UP
71 #define VIEWER_PAGE_DOWN BUTTON_DOWN
72 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
73 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
74 #define VIEWER_MENU BUTTON_F1
75 #define VIEWER_AUTOSCROLL BUTTON_PLAY
76 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
77 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
78 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
79 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
81 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
82 #define VIEWER_QUIT BUTTON_OFF
83 #define VIEWER_PAGE_UP BUTTON_UP
84 #define VIEWER_PAGE_DOWN BUTTON_DOWN
85 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
86 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
87 #define VIEWER_MENU BUTTON_F1
88 #define VIEWER_AUTOSCROLL BUTTON_SELECT
89 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
90 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
91 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
92 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
95 #elif CONFIG_KEYPAD == ONDIO_PAD
96 #define VIEWER_QUIT BUTTON_OFF
97 #define VIEWER_PAGE_UP BUTTON_UP
98 #define VIEWER_PAGE_DOWN BUTTON_DOWN
99 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
100 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
101 #define VIEWER_MENU (BUTTON_MENU|BUTTON_REPEAT)
102 #define VIEWER_AUTOSCROLL_PRE BUTTON_MENU
103 #define VIEWER_AUTOSCROLL (BUTTON_MENU|BUTTON_REL)
106 #elif CONFIG_KEYPAD == PLAYER_PAD
107 #define VIEWER_QUIT BUTTON_STOP
108 #define VIEWER_PAGE_UP BUTTON_LEFT
109 #define VIEWER_PAGE_DOWN BUTTON_RIGHT
110 #define VIEWER_SCREEN_LEFT (BUTTON_ON|BUTTON_LEFT)
111 #define VIEWER_SCREEN_RIGHT (BUTTON_ON|BUTTON_RIGHT)
112 #define VIEWER_MENU BUTTON_MENU
113 #define VIEWER_AUTOSCROLL BUTTON_PLAY
115 /* iRiver H1x0 && H3x0 keys */
116 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
117 (CONFIG_KEYPAD == IRIVER_H300_PAD)
118 #define VIEWER_QUIT BUTTON_OFF
119 #define VIEWER_PAGE_UP BUTTON_UP
120 #define VIEWER_PAGE_DOWN BUTTON_DOWN
121 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
122 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
123 #define VIEWER_MENU BUTTON_MODE
124 #define VIEWER_AUTOSCROLL BUTTON_SELECT
125 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
126 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
127 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
128 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
130 #define VIEWER_RC_QUIT BUTTON_RC_STOP
133 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
134 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
135 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
136 #define VIEWER_QUIT_PRE BUTTON_SELECT
137 #define VIEWER_QUIT (BUTTON_SELECT | BUTTON_MENU)
138 #define VIEWER_PAGE_UP BUTTON_SCROLL_BACK
139 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_FWD
140 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
141 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
142 #define VIEWER_MENU BUTTON_MENU
143 #define VIEWER_AUTOSCROLL BUTTON_PLAY
146 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
147 #define VIEWER_QUIT BUTTON_PLAY
148 #define VIEWER_PAGE_UP BUTTON_UP
149 #define VIEWER_PAGE_DOWN BUTTON_DOWN
150 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
151 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
152 #define VIEWER_MENU BUTTON_MODE
153 #define VIEWER_AUTOSCROLL BUTTON_SELECT
156 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
157 #define VIEWER_QUIT BUTTON_POWER
158 #define VIEWER_PAGE_UP BUTTON_UP
159 #define VIEWER_PAGE_DOWN BUTTON_DOWN
160 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
161 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
162 #define VIEWER_MENU BUTTON_SELECT
163 #define VIEWER_AUTOSCROLL BUTTON_PLAY
166 #elif CONFIG_KEYPAD == GIGABEAT_PAD
167 #define VIEWER_QUIT BUTTON_POWER
168 #define VIEWER_PAGE_UP BUTTON_UP
169 #define VIEWER_PAGE_DOWN BUTTON_DOWN
170 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
171 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
172 #define VIEWER_MENU BUTTON_MENU
173 #define VIEWER_AUTOSCROLL BUTTON_A
175 /* Sansa E200 keys */
176 #elif CONFIG_KEYPAD == SANSA_E200_PAD
177 #define VIEWER_QUIT BUTTON_POWER
178 #define VIEWER_PAGE_UP BUTTON_UP
179 #define VIEWER_PAGE_DOWN BUTTON_DOWN
180 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
181 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
182 #define VIEWER_MENU BUTTON_SELECT
183 #define VIEWER_AUTOSCROLL BUTTON_REC
184 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
185 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
187 /* Sansa Fuze keys */
188 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
189 #define VIEWER_QUIT (BUTTON_HOME|BUTTON_REPEAT)
190 #define VIEWER_PAGE_UP BUTTON_UP
191 #define VIEWER_PAGE_DOWN BUTTON_DOWN
192 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
193 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
194 #define VIEWER_MENU BUTTON_SELECT|BUTTON_REPEAT
195 #define VIEWER_AUTOSCROLL BUTTON_SELECT|BUTTON_DOWN
196 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
197 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
199 /* Sansa C200 keys */
200 #elif CONFIG_KEYPAD == SANSA_C200_PAD
201 #define VIEWER_QUIT BUTTON_POWER
202 #define VIEWER_PAGE_UP BUTTON_VOL_UP
203 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
204 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
205 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
206 #define VIEWER_MENU BUTTON_SELECT
207 #define VIEWER_AUTOSCROLL BUTTON_REC
208 #define VIEWER_LINE_UP BUTTON_UP
209 #define VIEWER_LINE_DOWN BUTTON_DOWN
211 /* Sansa Clip keys */
212 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
213 #define VIEWER_QUIT BUTTON_POWER
214 #define VIEWER_PAGE_UP BUTTON_VOL_UP
215 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
216 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
217 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
218 #define VIEWER_MENU BUTTON_SELECT
219 #define VIEWER_AUTOSCROLL BUTTON_HOME
220 #define VIEWER_LINE_UP BUTTON_UP
221 #define VIEWER_LINE_DOWN BUTTON_DOWN
223 /* Sansa M200 keys */
224 #elif CONFIG_KEYPAD == SANSA_M200_PAD
225 #define VIEWER_QUIT BUTTON_POWER
226 #define VIEWER_PAGE_UP BUTTON_VOL_UP
227 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
228 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
229 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
230 #define VIEWER_MENU (BUTTON_SELECT | BUTTON_UP)
231 #define VIEWER_AUTOSCROLL (BUTTON_SELECT | BUTTON_REL)
232 #define VIEWER_LINE_UP BUTTON_UP
233 #define VIEWER_LINE_DOWN BUTTON_DOWN
235 /* iriver H10 keys */
236 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
237 #define VIEWER_QUIT BUTTON_POWER
238 #define VIEWER_PAGE_UP BUTTON_SCROLL_UP
239 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_DOWN
240 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
241 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
242 #define VIEWER_MENU BUTTON_REW
243 #define VIEWER_AUTOSCROLL BUTTON_PLAY
246 #elif CONFIG_KEYPAD == MROBE500_PAD
247 #define VIEWER_QUIT BUTTON_POWER
248 #define VIEWER_PAGE_UP BUTTON_RC_PLAY
249 #define VIEWER_PAGE_DOWN BUTTON_RC_DOWN
250 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
251 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
252 #define VIEWER_MENU BUTTON_RC_HEART
253 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
256 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
257 #define VIEWER_QUIT BUTTON_BACK
258 #define VIEWER_PAGE_UP BUTTON_PREV
259 #define VIEWER_PAGE_DOWN BUTTON_NEXT
260 #define VIEWER_SCREEN_LEFT (BUTTON_PLAY | BUTTON_LEFT)
261 #define VIEWER_SCREEN_RIGHT (BUTTON_PLAY | BUTTON_RIGHT)
262 #define VIEWER_MENU BUTTON_MENU
263 #define VIEWER_AUTOSCROLL_PRE BUTTON_PLAY
264 #define VIEWER_AUTOSCROLL (BUTTON_PLAY|BUTTON_REL)
265 #define VIEWER_LINE_UP BUTTON_UP
266 #define VIEWER_LINE_DOWN BUTTON_DOWN
267 #define VIEWER_COLUMN_LEFT BUTTON_LEFT
268 #define VIEWER_COLUMN_RIGHT BUTTON_RIGHT
271 #elif CONFIG_KEYPAD == MROBE100_PAD
272 #define VIEWER_QUIT BUTTON_POWER
273 #define VIEWER_PAGE_UP BUTTON_UP
274 #define VIEWER_PAGE_DOWN BUTTON_DOWN
275 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
276 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
277 #define VIEWER_MENU BUTTON_MENU
278 #define VIEWER_AUTOSCROLL BUTTON_DISPLAY
281 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
282 #define VIEWER_QUIT BUTTON_RC_REC
283 #define VIEWER_PAGE_UP BUTTON_RC_VOL_UP
284 #define VIEWER_PAGE_DOWN BUTTON_RC_VOL_DOWN
285 #define VIEWER_SCREEN_LEFT BUTTON_RC_REW
286 #define VIEWER_SCREEN_RIGHT BUTTON_RC_FF
287 #define VIEWER_MENU BUTTON_RC_MENU
288 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
289 #define VIEWER_RC_QUIT BUTTON_REC
292 #elif CONFIG_KEYPAD == COWOND2_PAD
293 #define VIEWER_QUIT BUTTON_POWER
294 #define VIEWER_MENU BUTTON_MENU
296 #elif CONFIG_KEYPAD == IAUDIO67_PAD
297 #define VIEWER_QUIT BUTTON_POWER
298 #define VIEWER_PAGE_UP BUTTON_VOLUP
299 #define VIEWER_PAGE_DOWN BUTTON_VOLDOWN
300 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
301 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
302 #define VIEWER_MENU BUTTON_MENU
303 #define VIEWER_AUTOSCROLL BUTTON_PLAY
304 #define VIEWER_RC_QUIT BUTTON_STOP
306 /* Creative Zen Vision:M keys */
307 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
308 #define VIEWER_QUIT BUTTON_BACK
309 #define VIEWER_PAGE_UP BUTTON_UP
310 #define VIEWER_PAGE_DOWN BUTTON_DOWN
311 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
312 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
313 #define VIEWER_MENU BUTTON_MENU
314 #define VIEWER_AUTOSCROLL BUTTON_SELECT
316 /* Philips HDD1630 keys */
317 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
318 #define VIEWER_QUIT BUTTON_POWER
319 #define VIEWER_PAGE_UP BUTTON_UP
320 #define VIEWER_PAGE_DOWN BUTTON_DOWN
321 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
322 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
323 #define VIEWER_MENU BUTTON_MENU
324 #define VIEWER_AUTOSCROLL BUTTON_VIEW
326 /* Onda VX747 keys */
327 #elif CONFIG_KEYPAD == ONDAVX747_PAD
328 #define VIEWER_QUIT BUTTON_POWER
329 #define VIEWER_MENU BUTTON_MENU
332 #error No keymap defined!
335 #ifdef HAVE_TOUCHSCREEN
337 #define VIEWER_QUIT BUTTON_TOPLEFT
339 #ifndef VIEWER_PAGE_UP
340 #define VIEWER_PAGE_UP BUTTON_TOPMIDDLE
342 #ifndef VIEWER_PAGE_DOWN
343 #define VIEWER_PAGE_DOWN BUTTON_BOTTOMMIDDLE
345 #ifndef VIEWER_SCREEN_LEFT
346 #define VIEWER_SCREEN_LEFT BUTTON_MIDLEFT
348 #ifndef VIEWER_SCREEN_RIGHT
349 #define VIEWER_SCREEN_RIGHT BUTTON_MIDRIGHT
352 #define VIEWER_MENU BUTTON_TOPRIGHT
354 #ifndef VIEWER_AUTOSCROLL
355 #define VIEWER_AUTOSCROLL BUTTON_CENTER
359 /* stuff for the bookmarking */
360 struct bookmarked_file_info
{
363 char filename
[MAX_PATH
];
366 struct bookmark_file_data
{
367 signed int bookmarked_files_count
;
368 struct bookmarked_file_info bookmarks
[];
381 REFLOW
, /* won't be set on charcell LCD, must be last */
389 enum codepages encoding
;
391 #ifdef HAVE_LCD_BITMAP
402 #endif /* HAVE_LCD_BITMAP */
409 int autoscroll_speed
;
413 struct preferences prefs
;
414 struct preferences old_prefs
;
416 static unsigned char *buffer
;
417 static long buffer_size
;
418 static unsigned char line_break
[] = {0,0x20,9,0xB,0xC,'-'};
419 static int display_columns
; /* number of (pixel) columns on the display */
420 static int display_lines
; /* number of lines on the display */
421 static int draw_columns
; /* number of (pixel) columns available for text */
422 static int par_indent_spaces
; /* number of spaces to indent first paragraph */
424 static const char *file_name
;
425 static long file_size
;
426 static long start_position
; /* position in the file after the viewer is started */
427 static bool mac_text
;
428 static long file_pos
; /* Position of the top of the buffer in the file */
429 static unsigned char *buffer_end
; /*Set to BUFFER_END() when file_pos changes*/
430 static int max_line_len
;
431 static unsigned char *screen_top_ptr
;
432 static unsigned char *next_screen_ptr
;
433 static unsigned char *next_screen_to_draw_ptr
;
434 static unsigned char *next_line_ptr
;
435 #ifdef HAVE_LCD_BITMAP
436 static struct font
*pf
;
440 int glyph_width(int ch
)
445 #ifdef HAVE_LCD_BITMAP
446 return rb
->font_get_width(pf
, ch
);
452 unsigned char* get_ucs(const unsigned char* str
, unsigned short* ch
)
454 unsigned char utf8_tmp
[6];
457 if (prefs
.encoding
== UTF_8
)
458 return (unsigned char*)rb
->utf8decode(str
, ch
);
460 count
= BUFFER_OOB(str
+2)? 1:2;
461 rb
->iso_decode(str
, utf8_tmp
, prefs
.encoding
, count
);
462 rb
->utf8decode(utf8_tmp
, ch
);
464 #ifdef HAVE_LCD_BITMAP
465 if (prefs
.encoding
>= SJIS
&& *str
>= 0x80
466 && !(prefs
.encoding
== SJIS
&& *str
> 0xA0 && *str
< 0xE0))
467 return (unsigned char*)str
+2;
470 return (unsigned char*)str
+1;
476 #define ADVANCE_COUNTERS(c) { width += glyph_width(c); k++; }
477 #define LINE_IS_FULL ((k>=MAX_COLUMNS-1) ||( width >= draw_columns))
478 #define LINE_IS_NOT_FULL ((k<MAX_COLUMNS-1) &&( width < draw_columns))
479 static unsigned char* crop_at_width(const unsigned char* p
)
483 const unsigned char *oldp
= p
;
487 while (LINE_IS_NOT_FULL
) {
490 ADVANCE_COUNTERS(ch
);
493 return (unsigned char*)oldp
;
496 static unsigned char* find_first_feed(const unsigned char* p
, int size
)
500 for (i
=0; i
< size
; i
++)
502 return (unsigned char*) p
+i
;
507 static unsigned char* find_last_feed(const unsigned char* p
, int size
)
511 for (i
=size
-1; i
>=0; i
--)
513 return (unsigned char*) p
+i
;
518 static unsigned char* find_last_space(const unsigned char* p
, int size
)
522 k
= (prefs
.line_mode
==JOIN
) || (prefs
.line_mode
==REFLOW
) ? 0:1;
524 if (!BUFFER_OOB(&p
[size
]))
525 for (j
=k
; j
< ((int) sizeof(line_break
)) - 1; j
++)
526 if (p
[size
] == line_break
[j
])
527 return (unsigned char*) p
+size
;
529 for (i
=size
-1; i
>=0; i
--)
530 for (j
=k
; j
< (int) sizeof(line_break
); j
++)
532 if (!((p
[i
] == '-') && (prefs
.word_mode
== WRAP
)))
533 if (p
[i
] == line_break
[j
])
534 return (unsigned char*) p
+i
;
540 static unsigned char* find_next_line(const unsigned char* cur_line
, bool *is_short
)
542 const unsigned char *next_line
= NULL
;
543 int size
, i
, j
, k
, width
, search_len
, spaces
, newlines
;
547 if (is_short
!= NULL
)
550 if BUFFER_OOB(cur_line
)
553 if (prefs
.view_mode
== WIDE
) {
554 search_len
= MAX_WIDTH
;
556 else { /* prefs.view_mode == NARROW */
557 search_len
= crop_at_width(cur_line
) - cur_line
;
560 size
= BUFFER_OOB(cur_line
+search_len
) ? buffer_end
-cur_line
: search_len
;
562 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
)) {
563 /* Need to scan ahead and possibly increase search_len and size,
564 or possibly set next_line at second hard return in a row. */
567 for (j
=k
=width
=spaces
=newlines
=0; ; j
++) {
568 if (BUFFER_OOB(cur_line
+j
))
571 size
= search_len
= j
;
578 if (prefs
.line_mode
== REFLOW
) {
581 next_line
= cur_line
+ size
;
582 return (unsigned char*) next_line
;
584 if (j
==0) /* i=1 is intentional */
585 for (i
=0; i
<par_indent_spaces
; i
++)
586 ADVANCE_COUNTERS(' ');
588 if (!first_chars
) spaces
++;
594 next_line
= cur_line
+ size
- spaces
;
595 if (next_line
!= cur_line
)
596 return (unsigned char*) next_line
;
602 if (BUFFER_OOB(cur_line
+size
) || size
> 2*search_len
)
605 spaces
= first_chars
? 0:1;
609 if (prefs
.line_mode
==JOIN
|| newlines
>0) {
612 ADVANCE_COUNTERS(' ');
614 size
= search_len
= j
;
620 /* REFLOW, multiple spaces between words: count only
621 * one. If more are needed, they will be added
625 ADVANCE_COUNTERS(' ');
627 size
= search_len
= j
;
638 /* find first hard return */
639 next_line
= find_first_feed(cur_line
, size
);
642 if (next_line
== NULL
)
643 if (size
== search_len
) {
644 if (prefs
.word_mode
== WRAP
) /* Find last space */
645 next_line
= find_last_space(cur_line
, size
);
647 if (next_line
== NULL
)
648 next_line
= crop_at_width(cur_line
);
650 if (prefs
.word_mode
== WRAP
)
652 i
<WRAP_TRIM
&& isspace(next_line
[0]) && !BUFFER_OOB(next_line
);
657 if (prefs
.line_mode
== EXPAND
)
658 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
659 if (next_line
[0] == 0)
660 if (next_line
!= cur_line
)
661 return (unsigned char*) next_line
;
663 /* If next_line is pointing to a zero, increment it; i.e.,
664 leave the terminator at the end of cur_line. If pointing
665 to a hyphen, increment only if there is room to display
666 the hyphen on current line (won't apply in WIDE mode,
667 since it's guarenteed there won't be room). */
668 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
669 if (next_line
[0] == 0)/* ||
670 (next_line[0] == '-' && next_line-cur_line < draw_columns)) */
673 if (BUFFER_OOB(next_line
))
679 return (unsigned char*) next_line
;
682 static unsigned char* find_prev_line(const unsigned char* cur_line
)
684 const unsigned char *prev_line
= NULL
;
685 const unsigned char *p
;
687 if BUFFER_OOB(cur_line
)
690 /* To wrap consistently at the same places, we must
691 start with a known hard return, then work downwards.
692 We can either search backwards for a hard return,
693 or simply start wrapping downwards from top of buffer.
694 If current line is not near top of buffer, this is
695 a file with long lines (paragraphs). We would need to
696 read earlier sectors before we could decide how to
697 properly wrap the lines above the current line, but
698 it probably is not worth the disk access. Instead,
699 start with top of buffer and wrap down from there.
700 This may result in some lines wrapping at different
701 points from where they wrap when scrolling down.
702 If buffer is at top of file, start at top of buffer. */
704 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
))
705 prev_line
= p
= NULL
;
707 prev_line
= p
= find_last_feed(buffer
, cur_line
-buffer
-1);
708 /* Null means no line feeds in buffer above current line. */
710 if (prev_line
== NULL
)
711 if (BUFFER_BOF() || cur_line
- buffer
> READ_PREV_ZONE
)
712 prev_line
= p
= buffer
;
713 /* (else return NULL and read previous block) */
715 /* Wrap downwards until too far, then use the one before. */
716 while (p
< cur_line
&& p
!= NULL
) {
718 p
= find_next_line(prev_line
, NULL
);
721 if (BUFFER_OOB(prev_line
))
724 return (unsigned char*) prev_line
;
727 static void fill_buffer(long pos
, unsigned char* buf
, unsigned size
)
729 /* Read from file and preprocess the data */
730 /* To minimize disk access, always read on sector boundaries */
732 bool found_CR
= false;
734 rb
->lseek(fd
, pos
, SEEK_SET
);
735 numread
= rb
->read(fd
, buf
, size
);
736 rb
->button_clear_queue(); /* clear button queue */
738 for(i
= 0; i
< numread
; i
++) {
755 case 0: /* No break between case 0 and default, intentionally */
768 static int read_and_synch(int direction
)
770 /* Read next (or prev) block, and reposition global pointers. */
771 /* direction: 1 for down (i.e., further into file), -1 for up */
772 int move_size
, move_vector
, offset
;
773 unsigned char *fill_buf
;
775 if (direction
== -1) /* up */ {
776 move_size
= SMALL_BLOCK_SIZE
;
778 fill_buf
= TOP_SECTOR
;
779 rb
->memcpy(BOTTOM_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
780 rb
->memcpy(MID_SECTOR
, TOP_SECTOR
, SMALL_BLOCK_SIZE
);
783 if (prefs
.view_mode
== WIDE
) {
784 /* WIDE mode needs more buffer so we have to read smaller blocks */
785 move_size
= SMALL_BLOCK_SIZE
;
786 offset
= LARGE_BLOCK_SIZE
;
787 fill_buf
= BOTTOM_SECTOR
;
788 rb
->memcpy(TOP_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
789 rb
->memcpy(MID_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
792 move_size
= LARGE_BLOCK_SIZE
;
793 offset
= SMALL_BLOCK_SIZE
;
794 fill_buf
= MID_SECTOR
;
795 rb
->memcpy(TOP_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
798 move_vector
= direction
* move_size
;
799 screen_top_ptr
-= move_vector
;
800 file_pos
+= move_vector
;
801 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
802 fill_buffer(file_pos
+ offset
, fill_buf
, move_size
);
806 static void viewer_scroll_up(void)
810 p
= find_prev_line(screen_top_ptr
);
811 if (p
== NULL
&& !BUFFER_BOF()) {
813 p
= find_prev_line(screen_top_ptr
);
819 static void viewer_scroll_down(void)
821 if (next_screen_ptr
!= NULL
)
822 screen_top_ptr
= next_line_ptr
;
825 #ifdef HAVE_LCD_BITMAP
826 static void viewer_scrollbar(void) {
827 int items
, min_shown
, max_shown
;
829 items
= (int) file_size
; /* (SH1 int is same as long) */
830 min_shown
= (int) file_pos
+ (screen_top_ptr
- buffer
);
832 if (next_screen_ptr
== NULL
)
835 max_shown
= min_shown
+ (next_screen_ptr
- screen_top_ptr
);
837 rb
->gui_scrollbar_draw(rb
->screens
[SCREEN_MAIN
],0, 0, SCROLLBAR_WIDTH
-1,
838 LCD_HEIGHT
, items
, min_shown
, max_shown
, VERTICAL
);
842 static void viewer_draw(int col
)
844 int i
, j
, k
, line_len
, line_width
, resynch_move
, spaces
, left_col
=0;
845 int width
, extra_spaces
, indent_spaces
, spaces_per_word
;
846 bool multiple_spacing
, line_is_short
;
848 unsigned char *str
, *oldstr
;
849 unsigned char *line_begin
;
850 unsigned char *line_end
;
852 unsigned char scratch_buffer
[MAX_COLUMNS
+ 1];
853 unsigned char utf8_buffer
[MAX_COLUMNS
*4 + 1];
854 unsigned char *endptr
;
856 /* If col==-1 do all calculations but don't display */
858 #ifdef HAVE_LCD_BITMAP
859 left_col
= prefs
.need_scrollbar
? SCROLLBAR_WIDTH
:0;
863 rb
->lcd_clear_display();
866 line_begin
= line_end
= screen_top_ptr
;
868 for (i
= 0; i
< display_lines
; i
++) {
869 if (BUFFER_OOB(line_end
))
870 break; /* Happens after display last line at BUFFER_EOF() */
872 line_begin
= line_end
;
873 line_end
= find_next_line(line_begin
, &line_is_short
);
875 if (line_end
== NULL
) {
877 if (i
< display_lines
- 1 && !BUFFER_BOF()) {
879 rb
->lcd_clear_display();
881 for (; i
< display_lines
- 1; i
++)
884 line_begin
= line_end
= screen_top_ptr
;
889 line_end
= buffer_end
;
893 resynch_move
= read_and_synch(1); /* Read block & move ptrs */
894 line_begin
-= resynch_move
;
896 next_line_ptr
-= resynch_move
;
898 line_end
= find_next_line(line_begin
, NULL
);
899 if (line_end
== NULL
) /* Should not really happen */
903 line_len
= line_end
- line_begin
;
905 /* calculate line_len */
906 str
= oldstr
= line_begin
;
908 while (str
< line_end
) {
910 str
= crop_at_width(str
);
913 line_width
= j
*draw_columns
;
914 while (oldstr
< line_end
) {
915 oldstr
= get_ucs(oldstr
, &ch
);
916 line_width
+= glyph_width(ch
);
919 if (prefs
.line_mode
== JOIN
) {
920 if (line_begin
[0] == 0) {
922 if (prefs
.word_mode
== CHOP
)
927 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
928 if (k
== MAX_COLUMNS
)
938 scratch_buffer
[k
++] = ' ';
943 scratch_buffer
[k
++] = ' ';
944 if (k
== MAX_COLUMNS
- 1)
947 scratch_buffer
[k
++] = c
;
952 scratch_buffer
[k
] = 0;
953 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
954 prefs
.encoding
, draw_columns
/glyph_width('i'));
958 else if (prefs
.line_mode
== REFLOW
) {
959 if (line_begin
[0] == 0) {
961 if (prefs
.word_mode
== CHOP
)
968 if (!line_is_short
) {
969 multiple_spacing
= false;
971 for (str
= line_begin
; str
< line_end
; ) {
972 str
= get_ucs(str
, &ch
);
976 if ((str
== line_begin
) && (prefs
.word_mode
==WRAP
))
977 /* special case: indent the paragraph,
978 * don't count spaces */
979 indent_spaces
= par_indent_spaces
;
980 else if (!multiple_spacing
)
982 multiple_spacing
= true;
985 multiple_spacing
= false;
986 width
+= glyph_width(ch
);
990 if (multiple_spacing
) spaces
--;
993 /* total number of spaces to insert between words */
994 extra_spaces
= (draw_columns
-width
)/glyph_width(' ')
996 /* number of spaces between each word*/
997 spaces_per_word
= extra_spaces
/ spaces
;
998 /* number of words with n+1 spaces (to fill up) */
999 extra_spaces
= extra_spaces
% spaces
;
1000 if (spaces_per_word
> 2) { /* too much spacing is awful */
1001 spaces_per_word
= 3;
1004 } else { /* this doesn't matter much... no spaces anyway */
1005 spaces_per_word
= extra_spaces
= 0;
1007 } else { /* end of a paragraph: don't fill line */
1008 spaces_per_word
= 1;
1012 multiple_spacing
= false;
1013 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
1014 if (k
== MAX_COLUMNS
)
1021 if (j
==0 && prefs
.word_mode
==WRAP
) { /* indent paragraph */
1022 for (j
=0; j
<par_indent_spaces
; j
++)
1023 scratch_buffer
[k
++] = ' ';
1026 else if (!multiple_spacing
) {
1027 for (width
= spaces
<extra_spaces
? -1:0; width
< spaces_per_word
; width
++)
1028 scratch_buffer
[k
++] = ' ';
1031 multiple_spacing
= true;
1034 scratch_buffer
[k
++] = c
;
1035 multiple_spacing
= false;
1041 scratch_buffer
[k
] = 0;
1042 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
1043 prefs
.encoding
, k
-col
);
1047 else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */
1049 if (line_width
> col
) {
1050 str
= oldstr
= line_begin
;
1053 while( (width
<draw_columns
) && (oldstr
<line_end
) )
1055 oldstr
= get_ucs(oldstr
, &ch
);
1057 k
-= glyph_width(ch
);
1058 line_begin
= oldstr
;
1060 width
+= glyph_width(ch
);
1064 if(prefs
.view_mode
==WIDE
)
1065 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1066 prefs
.encoding
, oldstr
-line_begin
);
1068 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1069 prefs
.encoding
, line_end
-line_begin
);
1073 if (col
!= -1 && line_width
> col
)
1074 #ifdef HAVE_LCD_BITMAP
1075 rb
->lcd_putsxy(left_col
, i
*pf
->height
, utf8_buffer
);
1077 rb
->lcd_puts(left_col
, i
, utf8_buffer
);
1079 if (line_width
> max_line_len
)
1080 max_line_len
= line_width
;
1083 next_line_ptr
= line_end
;
1085 next_screen_ptr
= line_end
;
1086 if (BUFFER_OOB(next_screen_ptr
))
1087 next_screen_ptr
= NULL
;
1089 #ifdef HAVE_LCD_BITMAP
1090 next_screen_to_draw_ptr
= prefs
.page_mode
==OVERLAP
? line_begin
: next_screen_ptr
;
1092 if (prefs
.need_scrollbar
)
1095 next_screen_to_draw_ptr
= next_screen_ptr
;
1102 static void viewer_top(void)
1104 /* Read top of file into buffer
1105 and point screen pointer to top */
1109 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1110 fill_buffer(0, buffer
, buffer_size
);
1113 screen_top_ptr
= buffer
;
1116 static void viewer_bottom(void)
1118 /* Read bottom of file into buffer
1119 and point screen pointer to bottom */
1122 if (file_size
> buffer_size
) {
1123 /* Find last buffer in file, round up to next sector boundary */
1124 last_sectors
= file_size
- buffer_size
+ SMALL_BLOCK_SIZE
;
1125 last_sectors
/= SMALL_BLOCK_SIZE
;
1126 last_sectors
*= SMALL_BLOCK_SIZE
;
1132 if (file_pos
!= last_sectors
)
1134 file_pos
= last_sectors
;
1135 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1136 fill_buffer(last_sectors
, buffer
, buffer_size
);
1139 screen_top_ptr
= buffer_end
-1;
1142 #ifdef HAVE_LCD_BITMAP
1143 static void init_need_scrollbar(void) {
1144 /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
1145 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
1147 prefs
.need_scrollbar
= NEED_SCROLLBAR();
1148 draw_columns
= prefs
.need_scrollbar
? display_columns
-SCROLLBAR_WIDTH
: display_columns
;
1149 par_indent_spaces
= draw_columns
/(5*glyph_width(' '));
1152 #define init_need_scrollbar()
1155 static bool viewer_init(void)
1157 #ifdef HAVE_LCD_BITMAP
1159 pf
= rb
->font_get(FONT_UI
);
1161 display_lines
= LCD_HEIGHT
/ pf
->height
;
1162 draw_columns
= display_columns
= LCD_WIDTH
;
1164 /* REAL fixed pitch :) all chars use up 1 cell */
1166 draw_columns
= display_columns
= 11;
1167 par_indent_spaces
= 2;
1170 fd
= rb
->open(file_name
, O_RDONLY
);
1174 file_size
= rb
->filesize(fd
);
1178 /* Init mac_text value used in processing buffer */
1184 static void viewer_default_settings(void)
1186 prefs
.word_mode
= WRAP
;
1187 prefs
.line_mode
= NORMAL
;
1188 prefs
.view_mode
= NARROW
;
1189 prefs
.scroll_mode
= PAGE
;
1190 #ifdef HAVE_LCD_BITMAP
1191 prefs
.page_mode
= NO_OVERLAP
;
1192 prefs
.scrollbar_mode
= SB_OFF
;
1194 prefs
.autoscroll_speed
= 1;
1195 /* Set codepage to system default */
1196 prefs
.encoding
= rb
->global_settings
->default_codepage
;
1199 static void viewer_load_settings(void) /* same name as global, but not the same file.. */
1202 struct bookmark_file_data
*data
;
1203 struct bookmarked_file_info this_bookmark
;
1205 /* read settings file */
1206 settings_fd
=rb
->open(SETTINGS_FILE
, O_RDONLY
);
1207 if ((settings_fd
>= 0) && (rb
->filesize(settings_fd
) == sizeof(struct preferences
)))
1209 rb
->read(settings_fd
, &prefs
, sizeof(struct preferences
));
1210 rb
->close(settings_fd
);
1214 /* load default settings if there is no settings file */
1215 viewer_default_settings();
1218 rb
->memcpy(&old_prefs
, &prefs
, sizeof(struct preferences
));
1220 data
= (struct bookmark_file_data
*)buffer
; /* grab the text buffer */
1221 data
->bookmarked_files_count
= 0;
1223 /* read bookmarks if file exists */
1224 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_RDONLY
);
1225 if (settings_fd
>= 0)
1227 /* figure out how many items to read */
1228 rb
->read(settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1229 if (data
->bookmarked_files_count
> MAX_BOOKMARKED_FILES
)
1230 data
->bookmarked_files_count
= MAX_BOOKMARKED_FILES
;
1231 rb
->read(settings_fd
, data
->bookmarks
,
1232 sizeof(struct bookmarked_file_info
) * data
->bookmarked_files_count
);
1233 rb
->close(settings_fd
);
1237 screen_top_ptr
= buffer
;
1239 /* check if current file is in list */
1240 for (i
=0; i
< data
->bookmarked_files_count
; i
++)
1242 if (!rb
->strcmp(file_name
, data
->bookmarks
[i
].filename
))
1244 int screen_pos
= data
->bookmarks
[i
].file_position
+ data
->bookmarks
[i
].top_ptr_pos
;
1245 int screen_top
= screen_pos
% buffer_size
;
1246 file_pos
= screen_pos
- screen_top
;
1247 screen_top_ptr
= buffer
+ screen_top
;
1252 this_bookmark
.file_position
= file_pos
;
1253 this_bookmark
.top_ptr_pos
= screen_top_ptr
- buffer
;
1255 rb
->memset(&this_bookmark
.filename
[0],0,MAX_PATH
);
1256 rb
->strcpy(this_bookmark
.filename
,file_name
);
1258 /* prevent potential slot overflow */
1259 if (i
>= data
->bookmarked_files_count
)
1261 if (i
< MAX_BOOKMARKED_FILES
)
1262 data
->bookmarked_files_count
++;
1264 i
= MAX_BOOKMARKED_FILES
-1;
1267 /* write bookmark file with spare slot in first position
1268 to be filled in by viewer_save_settings */
1269 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1270 if (settings_fd
>=0 )
1273 rb
->write (settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1275 /* write the current bookmark */
1276 rb
->write (settings_fd
, &this_bookmark
, sizeof(struct bookmarked_file_info
));
1278 /* write everything that was before this bookmark */
1279 rb
->write (settings_fd
, data
->bookmarks
, sizeof(struct bookmarked_file_info
)*i
);
1281 rb
->close(settings_fd
);
1284 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1286 if (BUFFER_OOB(screen_top_ptr
))
1288 screen_top_ptr
= buffer
;
1291 fill_buffer(file_pos
, buffer
, buffer_size
);
1293 /* remember the current position */
1294 start_position
= file_pos
+ screen_top_ptr
- buffer
;
1296 init_need_scrollbar();
1299 static void viewer_save_settings(void)/* same name as global, but not the same file.. */
1303 /* save the viewer settings if they have been changed */
1304 if (rb
->memcmp(&prefs
, &old_prefs
, sizeof(struct preferences
)))
1306 settings_fd
= rb
->creat(SETTINGS_FILE
); /* create the settings file */
1308 if (settings_fd
>= 0 )
1310 rb
->write (settings_fd
, &prefs
, sizeof(struct preferences
));
1311 rb
->close(settings_fd
);
1315 /* save the bookmark if the position has changed */
1316 if (file_pos
+ screen_top_ptr
- buffer
!= start_position
)
1318 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1320 if (settings_fd
>= 0 )
1322 struct bookmarked_file_info b
;
1323 b
.file_position
= file_pos
+ screen_top_ptr
- buffer
;
1324 b
.top_ptr_pos
= 0; /* this is only kept for legassy reasons */
1325 rb
->memset(&b
.filename
[0],0,MAX_PATH
);
1326 rb
->strcpy(b
.filename
,file_name
);
1327 rb
->lseek(settings_fd
,sizeof(signed int),SEEK_SET
);
1328 rb
->write (settings_fd
, &b
, sizeof(struct bookmarked_file_info
));
1329 rb
->close(settings_fd
);
1334 static void viewer_exit(void *parameter
)
1338 viewer_save_settings();
1342 static int col_limit(int col
)
1347 if (col
> max_line_len
- 2*glyph_width('o'))
1348 col
= max_line_len
- 2*glyph_width('o');
1353 /* settings helper functions */
1355 static bool encoding_setting(void)
1357 static struct opt_items names
[NUM_CODEPAGES
];
1360 for (idx
= 0; idx
< NUM_CODEPAGES
; idx
++)
1362 names
[idx
].string
= rb
->get_codepage_name(idx
);
1363 names
[idx
].voice_id
= -1;
1366 return rb
->set_option("Encoding", &prefs
.encoding
, INT
, names
,
1367 sizeof(names
) / sizeof(names
[0]), NULL
);
1370 static bool word_wrap_setting(void)
1372 static const struct opt_items names
[] = {
1374 {"Off (Chop Words)", -1},
1377 return rb
->set_option("Word Wrap", &prefs
.word_mode
, INT
,
1381 static bool line_mode_setting(void)
1383 static const struct opt_items names
[] = {
1386 {"Expand Lines", -1},
1387 #ifdef HAVE_LCD_BITMAP
1388 {"Reflow Lines", -1},
1392 return rb
->set_option("Line Mode", &prefs
.line_mode
, INT
, names
,
1393 sizeof(names
) / sizeof(names
[0]), NULL
);
1396 static bool view_mode_setting(void)
1398 static const struct opt_items names
[] = {
1399 {"No (Narrow)", -1},
1403 ret
= rb
->set_option("Wide View", &prefs
.view_mode
, INT
,
1405 if (prefs
.view_mode
== NARROW
)
1410 static bool scroll_mode_setting(void)
1412 static const struct opt_items names
[] = {
1413 {"Scroll by Page", -1},
1414 {"Scroll by Line", -1},
1417 return rb
->set_option("Scroll Mode", &prefs
.scroll_mode
, INT
,
1421 #ifdef HAVE_LCD_BITMAP
1422 static bool page_mode_setting(void)
1424 static const struct opt_items names
[] = {
1429 return rb
->set_option("Overlap Pages", &prefs
.page_mode
, INT
,
1433 static bool scrollbar_setting(void)
1435 static const struct opt_items names
[] = {
1440 return rb
->set_option("Show Scrollbar", &prefs
.scrollbar_mode
, INT
,
1445 static bool autoscroll_speed_setting(void)
1447 return rb
->set_int("Auto-scroll Speed", "", UNIT_INT
,
1448 &prefs
.autoscroll_speed
, NULL
, 1, 1, 10, NULL
);
1451 MENUITEM_FUNCTION(encoding_item
, 0, "Encoding", encoding_setting
,
1452 NULL
, NULL
, Icon_NOICON
);
1453 MENUITEM_FUNCTION(word_wrap_item
, 0, "Word Wrap", word_wrap_setting
,
1454 NULL
, NULL
, Icon_NOICON
);
1455 MENUITEM_FUNCTION(line_mode_item
, 0, "Line Mode", line_mode_setting
,
1456 NULL
, NULL
, Icon_NOICON
);
1457 MENUITEM_FUNCTION(view_mode_item
, 0, "Wide View", view_mode_setting
,
1458 NULL
, NULL
, Icon_NOICON
);
1459 #ifdef HAVE_LCD_BITMAP
1460 MENUITEM_FUNCTION(scrollbar_item
, 0, "Show Scrollbar", scrollbar_setting
,
1461 NULL
, NULL
, Icon_NOICON
);
1462 MENUITEM_FUNCTION(page_mode_item
, 0, "Overlap Pages", page_mode_setting
,
1463 NULL
, NULL
, Icon_NOICON
);
1465 MENUITEM_FUNCTION(scroll_mode_item
, 0, "Scroll Mode", scroll_mode_setting
,
1466 NULL
, NULL
, Icon_NOICON
);
1467 MENUITEM_FUNCTION(autoscroll_speed_item
, 0, "Auto-Scroll Speed",
1468 autoscroll_speed_setting
, NULL
, NULL
, Icon_NOICON
);
1469 MAKE_MENU(option_menu
, "Viewer Options", NULL
, Icon_NOICON
,
1470 &encoding_item
, &word_wrap_item
, &line_mode_item
, &view_mode_item
,
1471 #ifdef HAVE_LCD_BITMAP
1472 &scrollbar_item
, &page_mode_item
,
1474 &scroll_mode_item
, &autoscroll_speed_item
);
1476 static bool viewer_options_menu(void)
1479 result
= (rb
->do_menu(&option_menu
, NULL
, NULL
, false) == MENU_ATTACHED_USB
);
1481 #ifdef HAVE_LCD_BITMAP
1482 /* Show-scrollbar mode for current view-width mode */
1483 init_need_scrollbar();
1488 static void viewer_menu(void)
1491 MENUITEM_STRINGLIST(menu
, "Viewer Menu", NULL
,
1492 "Return", "Viewer Options",
1493 "Show Playback Menu", "Quit");
1495 result
= rb
->do_menu(&menu
, NULL
, NULL
, false);
1498 case 0: /* return */
1500 case 1: /* change settings */
1501 done
= viewer_options_menu();
1503 case 2: /* playback control */
1504 playback_control(NULL
);
1514 enum plugin_status
plugin_start(const void* file
)
1517 int lastbutton
= BUTTON_NONE
;
1518 bool autoscroll
= false;
1521 old_tick
= *rb
->current_tick
;
1523 /* get the plugin buffer */
1524 buffer
= rb
->plugin_get_buffer((size_t *)&buffer_size
);
1527 return PLUGIN_ERROR
;
1532 rb
->splash(HZ
, "Error opening file.");
1533 return PLUGIN_ERROR
;
1536 viewer_load_settings(); /* load the preferences and bookmark */
1539 rb
->lcd_set_backdrop(NULL
);
1548 if(old_tick
<= *rb
->current_tick
- (110-prefs
.autoscroll_speed
*10))
1550 viewer_scroll_down();
1552 old_tick
= *rb
->current_tick
;
1556 button
= rb
->button_get_w_tmo(HZ
/10);
1562 case VIEWER_AUTOSCROLL
:
1563 #ifdef VIEWER_AUTOSCROLL_PRE
1564 if (lastbutton
!= VIEWER_AUTOSCROLL_PRE
)
1567 autoscroll
= !autoscroll
;
1570 case VIEWER_PAGE_UP
:
1571 case VIEWER_PAGE_UP
| BUTTON_REPEAT
:
1572 if (prefs
.scroll_mode
== PAGE
)
1575 #ifdef HAVE_LCD_BITMAP
1576 for (i
= prefs
.page_mode
==OVERLAP
? 1:0; i
< display_lines
; i
++)
1578 for (i
= 0; i
< display_lines
; i
++)
1584 old_tick
= *rb
->current_tick
;
1588 case VIEWER_PAGE_DOWN
:
1589 case VIEWER_PAGE_DOWN
| BUTTON_REPEAT
:
1590 if (prefs
.scroll_mode
== PAGE
)
1593 if (next_screen_ptr
!= NULL
)
1594 screen_top_ptr
= next_screen_to_draw_ptr
;
1597 viewer_scroll_down();
1598 old_tick
= *rb
->current_tick
;
1602 case VIEWER_SCREEN_LEFT
:
1603 case VIEWER_SCREEN_LEFT
| BUTTON_REPEAT
:
1604 if (prefs
.view_mode
== WIDE
) {
1606 col
-= draw_columns
;
1607 col
= col_limit(col
);
1609 else { /* prefs.view_mode == NARROW */
1617 case VIEWER_SCREEN_RIGHT
:
1618 case VIEWER_SCREEN_RIGHT
| BUTTON_REPEAT
:
1619 if (prefs
.view_mode
== WIDE
) {
1621 col
+= draw_columns
;
1622 col
= col_limit(col
);
1624 else { /* prefs.view_mode == NARROW */
1625 /* Bottom of file */
1632 #ifdef VIEWER_LINE_UP
1633 case VIEWER_LINE_UP
:
1634 case VIEWER_LINE_UP
| BUTTON_REPEAT
:
1635 /* Scroll up one line */
1637 old_tick
= *rb
->current_tick
;
1641 case VIEWER_LINE_DOWN
:
1642 case VIEWER_LINE_DOWN
| BUTTON_REPEAT
:
1643 /* Scroll down one line */
1644 if (next_screen_ptr
!= NULL
)
1645 screen_top_ptr
= next_line_ptr
;
1646 old_tick
= *rb
->current_tick
;
1650 #ifdef VIEWER_COLUMN_LEFT
1651 case VIEWER_COLUMN_LEFT
:
1652 case VIEWER_COLUMN_LEFT
| BUTTON_REPEAT
:
1653 if (prefs
.view_mode
== WIDE
) {
1654 /* Scroll left one column */
1655 col
-= glyph_width('o');
1656 col
= col_limit(col
);
1661 case VIEWER_COLUMN_RIGHT
:
1662 case VIEWER_COLUMN_RIGHT
| BUTTON_REPEAT
:
1663 if (prefs
.view_mode
== WIDE
) {
1664 /* Scroll right one column */
1665 col
+= glyph_width('o');
1666 col
= col_limit(col
);
1672 #ifdef VIEWER_RC_QUIT
1673 case VIEWER_RC_QUIT
:
1681 if (rb
->default_event_handler_ex(button
, viewer_exit
, NULL
)
1682 == SYS_USB_CONNECTED
)
1683 return PLUGIN_USB_CONNECTED
;
1686 if (button
!= BUTTON_NONE
)
1688 lastbutton
= button
;