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 #undef SCROLLBAR_WIDTH
41 #define SCROLLBAR_WIDTH rb->global_settings->scrollbar_width
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 Fuze keys */
189 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
190 #define VIEWER_QUIT (BUTTON_HOME|BUTTON_REPEAT)
191 #define VIEWER_PAGE_UP BUTTON_UP
192 #define VIEWER_PAGE_DOWN BUTTON_DOWN
193 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
194 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
195 #define VIEWER_MENU BUTTON_SELECT|BUTTON_REPEAT
196 #define VIEWER_AUTOSCROLL BUTTON_SELECT|BUTTON_DOWN
197 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
198 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
200 /* Sansa C200 keys */
201 #elif CONFIG_KEYPAD == SANSA_C200_PAD
202 #define VIEWER_QUIT BUTTON_POWER
203 #define VIEWER_PAGE_UP BUTTON_VOL_UP
204 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
205 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
206 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
207 #define VIEWER_MENU BUTTON_SELECT
208 #define VIEWER_AUTOSCROLL BUTTON_REC
209 #define VIEWER_LINE_UP BUTTON_UP
210 #define VIEWER_LINE_DOWN BUTTON_DOWN
212 /* Sansa Clip keys */
213 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
214 #define VIEWER_QUIT BUTTON_POWER
215 #define VIEWER_PAGE_UP BUTTON_VOL_UP
216 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
217 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
218 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
219 #define VIEWER_MENU BUTTON_SELECT
220 #define VIEWER_AUTOSCROLL BUTTON_HOME
221 #define VIEWER_LINE_UP BUTTON_UP
222 #define VIEWER_LINE_DOWN BUTTON_DOWN
224 /* Sansa M200 keys */
225 #elif CONFIG_KEYPAD == SANSA_M200_PAD
226 #define VIEWER_QUIT BUTTON_POWER
227 #define VIEWER_PAGE_UP BUTTON_VOL_UP
228 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
229 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
230 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
231 #define VIEWER_MENU (BUTTON_SELECT | BUTTON_UP)
232 #define VIEWER_AUTOSCROLL (BUTTON_SELECT | BUTTON_REL)
233 #define VIEWER_LINE_UP BUTTON_UP
234 #define VIEWER_LINE_DOWN BUTTON_DOWN
236 /* iriver H10 keys */
237 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
238 #define VIEWER_QUIT BUTTON_POWER
239 #define VIEWER_PAGE_UP BUTTON_SCROLL_UP
240 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_DOWN
241 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
242 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
243 #define VIEWER_MENU BUTTON_REW
244 #define VIEWER_AUTOSCROLL BUTTON_PLAY
247 #elif CONFIG_KEYPAD == MROBE500_PAD
248 #define VIEWER_QUIT BUTTON_POWER
249 #define VIEWER_PAGE_UP BUTTON_RC_PLAY
250 #define VIEWER_PAGE_DOWN BUTTON_RC_DOWN
251 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
252 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
253 #define VIEWER_MENU BUTTON_RC_HEART
254 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
257 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
258 #define VIEWER_QUIT BUTTON_BACK
259 #define VIEWER_PAGE_UP BUTTON_PREV
260 #define VIEWER_PAGE_DOWN BUTTON_NEXT
261 #define VIEWER_SCREEN_LEFT (BUTTON_PLAY | BUTTON_LEFT)
262 #define VIEWER_SCREEN_RIGHT (BUTTON_PLAY | BUTTON_RIGHT)
263 #define VIEWER_MENU BUTTON_MENU
264 #define VIEWER_AUTOSCROLL_PRE BUTTON_PLAY
265 #define VIEWER_AUTOSCROLL (BUTTON_PLAY|BUTTON_REL)
266 #define VIEWER_LINE_UP BUTTON_UP
267 #define VIEWER_LINE_DOWN BUTTON_DOWN
268 #define VIEWER_COLUMN_LEFT BUTTON_LEFT
269 #define VIEWER_COLUMN_RIGHT BUTTON_RIGHT
272 #elif CONFIG_KEYPAD == MROBE100_PAD
273 #define VIEWER_QUIT BUTTON_POWER
274 #define VIEWER_PAGE_UP BUTTON_UP
275 #define VIEWER_PAGE_DOWN BUTTON_DOWN
276 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
277 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
278 #define VIEWER_MENU BUTTON_MENU
279 #define VIEWER_AUTOSCROLL BUTTON_DISPLAY
282 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
283 #define VIEWER_QUIT BUTTON_RC_REC
284 #define VIEWER_PAGE_UP BUTTON_RC_VOL_UP
285 #define VIEWER_PAGE_DOWN BUTTON_RC_VOL_DOWN
286 #define VIEWER_SCREEN_LEFT BUTTON_RC_REW
287 #define VIEWER_SCREEN_RIGHT BUTTON_RC_FF
288 #define VIEWER_MENU BUTTON_RC_MENU
289 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
290 #define VIEWER_RC_QUIT BUTTON_REC
293 #elif CONFIG_KEYPAD == COWOND2_PAD
294 #define VIEWER_QUIT BUTTON_POWER
295 #define VIEWER_MENU BUTTON_MENU
297 #elif CONFIG_KEYPAD == IAUDIO67_PAD
298 #define VIEWER_QUIT BUTTON_POWER
299 #define VIEWER_PAGE_UP BUTTON_VOLUP
300 #define VIEWER_PAGE_DOWN BUTTON_VOLDOWN
301 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
302 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
303 #define VIEWER_MENU BUTTON_MENU
304 #define VIEWER_AUTOSCROLL BUTTON_PLAY
305 #define VIEWER_RC_QUIT BUTTON_STOP
307 /* Creative Zen Vision:M keys */
308 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
309 #define VIEWER_QUIT BUTTON_BACK
310 #define VIEWER_PAGE_UP BUTTON_UP
311 #define VIEWER_PAGE_DOWN BUTTON_DOWN
312 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
313 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
314 #define VIEWER_MENU BUTTON_MENU
315 #define VIEWER_AUTOSCROLL BUTTON_SELECT
317 /* Philips HDD1630 keys */
318 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
319 #define VIEWER_QUIT BUTTON_POWER
320 #define VIEWER_PAGE_UP BUTTON_UP
321 #define VIEWER_PAGE_DOWN BUTTON_DOWN
322 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
323 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
324 #define VIEWER_MENU BUTTON_MENU
325 #define VIEWER_AUTOSCROLL BUTTON_VIEW
327 /* Onda VX747 keys */
328 #elif CONFIG_KEYPAD == ONDAVX747_PAD
329 #define VIEWER_QUIT BUTTON_POWER
330 #define VIEWER_MENU BUTTON_MENU
332 /* Onda VX777 keys */
333 #elif CONFIG_KEYPAD == ONDAVX777_PAD
334 #define VIEWER_QUIT BUTTON_POWER
336 /* SAMSUNG YH-820 / YH-920 / YH-925 keys */
337 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
338 #define VIEWER_QUIT BUTTON_REC
339 #define VIEWER_PAGE_UP BUTTON_UP
340 #define VIEWER_PAGE_DOWN BUTTON_DOWN
341 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
342 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
343 #define VIEWER_MENU BUTTON_PLAY
344 #define VIEWER_AUTOSCROLL BUTTON_REW
347 #error No keymap defined!
350 #ifdef HAVE_TOUCHSCREEN
352 #define VIEWER_QUIT BUTTON_TOPLEFT
354 #ifndef VIEWER_PAGE_UP
355 #define VIEWER_PAGE_UP BUTTON_TOPMIDDLE
357 #ifndef VIEWER_PAGE_DOWN
358 #define VIEWER_PAGE_DOWN BUTTON_BOTTOMMIDDLE
360 #ifndef VIEWER_SCREEN_LEFT
361 #define VIEWER_SCREEN_LEFT BUTTON_MIDLEFT
363 #ifndef VIEWER_SCREEN_RIGHT
364 #define VIEWER_SCREEN_RIGHT BUTTON_MIDRIGHT
367 #define VIEWER_MENU BUTTON_TOPRIGHT
369 #ifndef VIEWER_AUTOSCROLL
370 #define VIEWER_AUTOSCROLL BUTTON_CENTER
374 /* stuff for the bookmarking */
375 struct bookmarked_file_info
{
378 char filename
[MAX_PATH
];
381 struct bookmark_file_data
{
382 signed int bookmarked_files_count
;
383 struct bookmarked_file_info bookmarks
[];
396 REFLOW
, /* won't be set on charcell LCD, must be last */
404 enum codepages encoding
;
406 #ifdef HAVE_LCD_BITMAP
417 #endif /* HAVE_LCD_BITMAP */
424 int autoscroll_speed
;
428 struct preferences prefs
;
429 struct preferences old_prefs
;
431 static unsigned char *buffer
;
432 static long buffer_size
;
433 static unsigned char line_break
[] = {0,0x20,9,0xB,0xC,'-'};
434 static int display_columns
; /* number of (pixel) columns on the display */
435 static int display_lines
; /* number of lines on the display */
436 static int draw_columns
; /* number of (pixel) columns available for text */
437 static int par_indent_spaces
; /* number of spaces to indent first paragraph */
439 static const char *file_name
;
440 static long file_size
;
441 static long start_position
; /* position in the file after the viewer is started */
442 static bool mac_text
;
443 static long file_pos
; /* Position of the top of the buffer in the file */
444 static unsigned char *buffer_end
; /*Set to BUFFER_END() when file_pos changes*/
445 static int max_line_len
;
446 static unsigned char *screen_top_ptr
;
447 static unsigned char *next_screen_ptr
;
448 static unsigned char *next_screen_to_draw_ptr
;
449 static unsigned char *next_line_ptr
;
450 #ifdef HAVE_LCD_BITMAP
451 static struct font
*pf
;
455 int glyph_width(int ch
)
460 #ifdef HAVE_LCD_BITMAP
461 return rb
->font_get_width(pf
, ch
);
467 unsigned char* get_ucs(const unsigned char* str
, unsigned short* ch
)
469 unsigned char utf8_tmp
[6];
472 if (prefs
.encoding
== UTF_8
)
473 return (unsigned char*)rb
->utf8decode(str
, ch
);
475 count
= BUFFER_OOB(str
+2)? 1:2;
476 rb
->iso_decode(str
, utf8_tmp
, prefs
.encoding
, count
);
477 rb
->utf8decode(utf8_tmp
, ch
);
479 #ifdef HAVE_LCD_BITMAP
480 if (prefs
.encoding
>= SJIS
&& *str
>= 0x80
481 && !(prefs
.encoding
== SJIS
&& *str
> 0xA0 && *str
< 0xE0))
482 return (unsigned char*)str
+2;
485 return (unsigned char*)str
+1;
491 #define ADVANCE_COUNTERS(c) { width += glyph_width(c); k++; }
492 #define LINE_IS_FULL ((k>=MAX_COLUMNS-1) ||( width >= draw_columns))
493 #define LINE_IS_NOT_FULL ((k<MAX_COLUMNS-1) &&( width < draw_columns))
494 static unsigned char* crop_at_width(const unsigned char* p
)
498 const unsigned char *oldp
= p
;
502 while (LINE_IS_NOT_FULL
) {
505 ADVANCE_COUNTERS(ch
);
508 return (unsigned char*)oldp
;
511 static unsigned char* find_first_feed(const unsigned char* p
, int size
)
515 for (i
=0; i
< size
; i
++)
517 return (unsigned char*) p
+i
;
522 static unsigned char* find_last_feed(const unsigned char* p
, int size
)
526 for (i
=size
-1; i
>=0; i
--)
528 return (unsigned char*) p
+i
;
533 static unsigned char* find_last_space(const unsigned char* p
, int size
)
537 k
= (prefs
.line_mode
==JOIN
) || (prefs
.line_mode
==REFLOW
) ? 0:1;
539 if (!BUFFER_OOB(&p
[size
]))
540 for (j
=k
; j
< ((int) sizeof(line_break
)) - 1; j
++)
541 if (p
[size
] == line_break
[j
])
542 return (unsigned char*) p
+size
;
544 for (i
=size
-1; i
>=0; i
--)
545 for (j
=k
; j
< (int) sizeof(line_break
); j
++)
547 if (!((p
[i
] == '-') && (prefs
.word_mode
== WRAP
)))
548 if (p
[i
] == line_break
[j
])
549 return (unsigned char*) p
+i
;
555 static unsigned char* find_next_line(const unsigned char* cur_line
, bool *is_short
)
557 const unsigned char *next_line
= NULL
;
558 int size
, i
, j
, k
, width
, search_len
, spaces
, newlines
;
562 if (is_short
!= NULL
)
565 if BUFFER_OOB(cur_line
)
568 if (prefs
.view_mode
== WIDE
) {
569 search_len
= MAX_WIDTH
;
571 else { /* prefs.view_mode == NARROW */
572 search_len
= crop_at_width(cur_line
) - cur_line
;
575 size
= BUFFER_OOB(cur_line
+search_len
) ? buffer_end
-cur_line
: search_len
;
577 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
)) {
578 /* Need to scan ahead and possibly increase search_len and size,
579 or possibly set next_line at second hard return in a row. */
582 for (j
=k
=width
=spaces
=newlines
=0; ; j
++) {
583 if (BUFFER_OOB(cur_line
+j
))
586 size
= search_len
= j
;
593 if (prefs
.line_mode
== REFLOW
) {
596 next_line
= cur_line
+ size
;
597 return (unsigned char*) next_line
;
599 if (j
==0) /* i=1 is intentional */
600 for (i
=0; i
<par_indent_spaces
; i
++)
601 ADVANCE_COUNTERS(' ');
603 if (!first_chars
) spaces
++;
609 next_line
= cur_line
+ size
- spaces
;
610 if (next_line
!= cur_line
)
611 return (unsigned char*) next_line
;
617 if (BUFFER_OOB(cur_line
+size
) || size
> 2*search_len
)
620 spaces
= first_chars
? 0:1;
624 if (prefs
.line_mode
==JOIN
|| newlines
>0) {
627 ADVANCE_COUNTERS(' ');
629 size
= search_len
= j
;
635 /* REFLOW, multiple spaces between words: count only
636 * one. If more are needed, they will be added
640 ADVANCE_COUNTERS(' ');
642 size
= search_len
= j
;
653 /* find first hard return */
654 next_line
= find_first_feed(cur_line
, size
);
657 if (next_line
== NULL
)
658 if (size
== search_len
) {
659 if (prefs
.word_mode
== WRAP
) /* Find last space */
660 next_line
= find_last_space(cur_line
, size
);
662 if (next_line
== NULL
)
663 next_line
= crop_at_width(cur_line
);
665 if (prefs
.word_mode
== WRAP
)
667 i
<WRAP_TRIM
&& isspace(next_line
[0]) && !BUFFER_OOB(next_line
);
672 if (prefs
.line_mode
== EXPAND
)
673 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
674 if (next_line
[0] == 0)
675 if (next_line
!= cur_line
)
676 return (unsigned char*) next_line
;
678 /* If next_line is pointing to a zero, increment it; i.e.,
679 leave the terminator at the end of cur_line. If pointing
680 to a hyphen, increment only if there is room to display
681 the hyphen on current line (won't apply in WIDE mode,
682 since it's guarenteed there won't be room). */
683 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
684 if (next_line
[0] == 0)/* ||
685 (next_line[0] == '-' && next_line-cur_line < draw_columns)) */
688 if (BUFFER_OOB(next_line
))
694 return (unsigned char*) next_line
;
697 static unsigned char* find_prev_line(const unsigned char* cur_line
)
699 const unsigned char *prev_line
= NULL
;
700 const unsigned char *p
;
702 if BUFFER_OOB(cur_line
)
705 /* To wrap consistently at the same places, we must
706 start with a known hard return, then work downwards.
707 We can either search backwards for a hard return,
708 or simply start wrapping downwards from top of buffer.
709 If current line is not near top of buffer, this is
710 a file with long lines (paragraphs). We would need to
711 read earlier sectors before we could decide how to
712 properly wrap the lines above the current line, but
713 it probably is not worth the disk access. Instead,
714 start with top of buffer and wrap down from there.
715 This may result in some lines wrapping at different
716 points from where they wrap when scrolling down.
717 If buffer is at top of file, start at top of buffer. */
719 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
))
720 prev_line
= p
= NULL
;
722 prev_line
= p
= find_last_feed(buffer
, cur_line
-buffer
-1);
723 /* Null means no line feeds in buffer above current line. */
725 if (prev_line
== NULL
)
726 if (BUFFER_BOF() || cur_line
- buffer
> READ_PREV_ZONE
)
727 prev_line
= p
= buffer
;
728 /* (else return NULL and read previous block) */
730 /* Wrap downwards until too far, then use the one before. */
731 while (p
< cur_line
&& p
!= NULL
) {
733 p
= find_next_line(prev_line
, NULL
);
736 if (BUFFER_OOB(prev_line
))
739 return (unsigned char*) prev_line
;
742 static void fill_buffer(long pos
, unsigned char* buf
, unsigned size
)
744 /* Read from file and preprocess the data */
745 /* To minimize disk access, always read on sector boundaries */
747 bool found_CR
= false;
749 rb
->lseek(fd
, pos
, SEEK_SET
);
750 numread
= rb
->read(fd
, buf
, size
);
751 rb
->button_clear_queue(); /* clear button queue */
753 for(i
= 0; i
< numread
; i
++) {
770 case 0: /* No break between case 0 and default, intentionally */
783 static int read_and_synch(int direction
)
785 /* Read next (or prev) block, and reposition global pointers. */
786 /* direction: 1 for down (i.e., further into file), -1 for up */
787 int move_size
, move_vector
, offset
;
788 unsigned char *fill_buf
;
790 if (direction
== -1) /* up */ {
791 move_size
= SMALL_BLOCK_SIZE
;
793 fill_buf
= TOP_SECTOR
;
794 rb
->memcpy(BOTTOM_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
795 rb
->memcpy(MID_SECTOR
, TOP_SECTOR
, SMALL_BLOCK_SIZE
);
798 if (prefs
.view_mode
== WIDE
) {
799 /* WIDE mode needs more buffer so we have to read smaller blocks */
800 move_size
= SMALL_BLOCK_SIZE
;
801 offset
= LARGE_BLOCK_SIZE
;
802 fill_buf
= BOTTOM_SECTOR
;
803 rb
->memcpy(TOP_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
804 rb
->memcpy(MID_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
807 move_size
= LARGE_BLOCK_SIZE
;
808 offset
= SMALL_BLOCK_SIZE
;
809 fill_buf
= MID_SECTOR
;
810 rb
->memcpy(TOP_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
813 move_vector
= direction
* move_size
;
814 screen_top_ptr
-= move_vector
;
815 file_pos
+= move_vector
;
816 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
817 fill_buffer(file_pos
+ offset
, fill_buf
, move_size
);
821 static void viewer_scroll_up(void)
825 p
= find_prev_line(screen_top_ptr
);
826 if (p
== NULL
&& !BUFFER_BOF()) {
828 p
= find_prev_line(screen_top_ptr
);
834 static void viewer_scroll_down(void)
836 if (next_screen_ptr
!= NULL
)
837 screen_top_ptr
= next_line_ptr
;
840 #ifdef HAVE_LCD_BITMAP
841 static void viewer_scrollbar(void) {
842 int items
, min_shown
, max_shown
;
844 items
= (int) file_size
; /* (SH1 int is same as long) */
845 min_shown
= (int) file_pos
+ (screen_top_ptr
- buffer
);
847 if (next_screen_ptr
== NULL
)
850 max_shown
= min_shown
+ (next_screen_ptr
- screen_top_ptr
);
852 rb
->gui_scrollbar_draw(rb
->screens
[SCREEN_MAIN
],0, 0, SCROLLBAR_WIDTH
-1,
853 LCD_HEIGHT
, items
, min_shown
, max_shown
, VERTICAL
);
857 static void viewer_draw(int col
)
859 int i
, j
, k
, line_len
, line_width
, resynch_move
, spaces
, left_col
=0;
860 int width
, extra_spaces
, indent_spaces
, spaces_per_word
;
861 bool multiple_spacing
, line_is_short
;
863 unsigned char *str
, *oldstr
;
864 unsigned char *line_begin
;
865 unsigned char *line_end
;
867 unsigned char scratch_buffer
[MAX_COLUMNS
+ 1];
868 unsigned char utf8_buffer
[MAX_COLUMNS
*4 + 1];
869 unsigned char *endptr
;
871 /* If col==-1 do all calculations but don't display */
873 #ifdef HAVE_LCD_BITMAP
874 left_col
= prefs
.need_scrollbar
? SCROLLBAR_WIDTH
:0;
878 rb
->lcd_clear_display();
881 line_begin
= line_end
= screen_top_ptr
;
883 for (i
= 0; i
< display_lines
; i
++) {
884 if (BUFFER_OOB(line_end
))
885 break; /* Happens after display last line at BUFFER_EOF() */
887 line_begin
= line_end
;
888 line_end
= find_next_line(line_begin
, &line_is_short
);
890 if (line_end
== NULL
) {
892 if (i
< display_lines
- 1 && !BUFFER_BOF()) {
894 rb
->lcd_clear_display();
896 for (; i
< display_lines
- 1; i
++)
899 line_begin
= line_end
= screen_top_ptr
;
904 line_end
= buffer_end
;
908 resynch_move
= read_and_synch(1); /* Read block & move ptrs */
909 line_begin
-= resynch_move
;
911 next_line_ptr
-= resynch_move
;
913 line_end
= find_next_line(line_begin
, NULL
);
914 if (line_end
== NULL
) /* Should not really happen */
918 line_len
= line_end
- line_begin
;
920 /* calculate line_len */
921 str
= oldstr
= line_begin
;
923 while (str
< line_end
) {
925 str
= crop_at_width(str
);
928 line_width
= j
*draw_columns
;
929 while (oldstr
< line_end
) {
930 oldstr
= get_ucs(oldstr
, &ch
);
931 line_width
+= glyph_width(ch
);
934 if (prefs
.line_mode
== JOIN
) {
935 if (line_begin
[0] == 0) {
937 if (prefs
.word_mode
== CHOP
)
942 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
943 if (k
== MAX_COLUMNS
)
953 scratch_buffer
[k
++] = ' ';
958 scratch_buffer
[k
++] = ' ';
959 if (k
== MAX_COLUMNS
- 1)
962 scratch_buffer
[k
++] = c
;
967 scratch_buffer
[k
] = 0;
968 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
969 prefs
.encoding
, draw_columns
/glyph_width('i'));
973 else if (prefs
.line_mode
== REFLOW
) {
974 if (line_begin
[0] == 0) {
976 if (prefs
.word_mode
== CHOP
)
983 if (!line_is_short
) {
984 multiple_spacing
= false;
986 for (str
= line_begin
; str
< line_end
; ) {
987 str
= get_ucs(str
, &ch
);
991 if ((str
== line_begin
) && (prefs
.word_mode
==WRAP
))
992 /* special case: indent the paragraph,
993 * don't count spaces */
994 indent_spaces
= par_indent_spaces
;
995 else if (!multiple_spacing
)
997 multiple_spacing
= true;
1000 multiple_spacing
= false;
1001 width
+= glyph_width(ch
);
1005 if (multiple_spacing
) spaces
--;
1008 /* total number of spaces to insert between words */
1009 extra_spaces
= (draw_columns
-width
)/glyph_width(' ')
1011 /* number of spaces between each word*/
1012 spaces_per_word
= extra_spaces
/ spaces
;
1013 /* number of words with n+1 spaces (to fill up) */
1014 extra_spaces
= extra_spaces
% spaces
;
1015 if (spaces_per_word
> 2) { /* too much spacing is awful */
1016 spaces_per_word
= 3;
1019 } else { /* this doesn't matter much... no spaces anyway */
1020 spaces_per_word
= extra_spaces
= 0;
1022 } else { /* end of a paragraph: don't fill line */
1023 spaces_per_word
= 1;
1027 multiple_spacing
= false;
1028 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
1029 if (k
== MAX_COLUMNS
)
1036 if (j
==0 && prefs
.word_mode
==WRAP
) { /* indent paragraph */
1037 for (j
=0; j
<par_indent_spaces
; j
++)
1038 scratch_buffer
[k
++] = ' ';
1041 else if (!multiple_spacing
) {
1042 for (width
= spaces
<extra_spaces
? -1:0; width
< spaces_per_word
; width
++)
1043 scratch_buffer
[k
++] = ' ';
1046 multiple_spacing
= true;
1049 scratch_buffer
[k
++] = c
;
1050 multiple_spacing
= false;
1056 scratch_buffer
[k
] = 0;
1057 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
1058 prefs
.encoding
, k
-col
);
1062 else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */
1064 if (line_width
> col
) {
1065 str
= oldstr
= line_begin
;
1068 while( (width
<draw_columns
) && (oldstr
<line_end
) )
1070 oldstr
= get_ucs(oldstr
, &ch
);
1072 k
-= glyph_width(ch
);
1073 line_begin
= oldstr
;
1075 width
+= glyph_width(ch
);
1079 if(prefs
.view_mode
==WIDE
)
1080 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1081 prefs
.encoding
, oldstr
-line_begin
);
1083 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1084 prefs
.encoding
, line_end
-line_begin
);
1088 if (col
!= -1 && line_width
> col
)
1089 #ifdef HAVE_LCD_BITMAP
1090 rb
->lcd_putsxy(left_col
, i
*pf
->height
, utf8_buffer
);
1092 rb
->lcd_puts(left_col
, i
, utf8_buffer
);
1094 if (line_width
> max_line_len
)
1095 max_line_len
= line_width
;
1098 next_line_ptr
= line_end
;
1100 next_screen_ptr
= line_end
;
1101 if (BUFFER_OOB(next_screen_ptr
))
1102 next_screen_ptr
= NULL
;
1104 #ifdef HAVE_LCD_BITMAP
1105 next_screen_to_draw_ptr
= prefs
.page_mode
==OVERLAP
? line_begin
: next_screen_ptr
;
1107 if (prefs
.need_scrollbar
)
1110 next_screen_to_draw_ptr
= next_screen_ptr
;
1117 static void viewer_top(void)
1119 /* Read top of file into buffer
1120 and point screen pointer to top */
1124 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1125 fill_buffer(0, buffer
, buffer_size
);
1128 screen_top_ptr
= buffer
;
1131 static void viewer_bottom(void)
1133 /* Read bottom of file into buffer
1134 and point screen pointer to bottom */
1137 if (file_size
> buffer_size
) {
1138 /* Find last buffer in file, round up to next sector boundary */
1139 last_sectors
= file_size
- buffer_size
+ SMALL_BLOCK_SIZE
;
1140 last_sectors
/= SMALL_BLOCK_SIZE
;
1141 last_sectors
*= SMALL_BLOCK_SIZE
;
1147 if (file_pos
!= last_sectors
)
1149 file_pos
= last_sectors
;
1150 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1151 fill_buffer(last_sectors
, buffer
, buffer_size
);
1154 screen_top_ptr
= buffer_end
-1;
1157 #ifdef HAVE_LCD_BITMAP
1158 static void init_need_scrollbar(void) {
1159 /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
1160 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
1162 prefs
.need_scrollbar
= NEED_SCROLLBAR();
1163 draw_columns
= prefs
.need_scrollbar
? display_columns
-SCROLLBAR_WIDTH
: display_columns
;
1164 par_indent_spaces
= draw_columns
/(5*glyph_width(' '));
1167 #define init_need_scrollbar()
1170 static bool viewer_init(void)
1172 #ifdef HAVE_LCD_BITMAP
1174 pf
= rb
->font_get(FONT_UI
);
1176 display_lines
= LCD_HEIGHT
/ pf
->height
;
1177 draw_columns
= display_columns
= LCD_WIDTH
;
1179 /* REAL fixed pitch :) all chars use up 1 cell */
1181 draw_columns
= display_columns
= 11;
1182 par_indent_spaces
= 2;
1185 fd
= rb
->open(file_name
, O_RDONLY
);
1189 file_size
= rb
->filesize(fd
);
1193 /* Init mac_text value used in processing buffer */
1199 static void viewer_default_settings(void)
1201 prefs
.word_mode
= WRAP
;
1202 prefs
.line_mode
= NORMAL
;
1203 prefs
.view_mode
= NARROW
;
1204 prefs
.scroll_mode
= PAGE
;
1205 #ifdef HAVE_LCD_BITMAP
1206 prefs
.page_mode
= NO_OVERLAP
;
1207 prefs
.scrollbar_mode
= SB_OFF
;
1209 prefs
.autoscroll_speed
= 1;
1210 /* Set codepage to system default */
1211 prefs
.encoding
= rb
->global_settings
->default_codepage
;
1214 static void viewer_load_settings(void) /* same name as global, but not the same file.. */
1217 struct bookmark_file_data
*data
;
1218 struct bookmarked_file_info this_bookmark
;
1220 /* read settings file */
1221 settings_fd
=rb
->open(SETTINGS_FILE
, O_RDONLY
);
1222 if ((settings_fd
>= 0) && (rb
->filesize(settings_fd
) == sizeof(struct preferences
)))
1224 rb
->read(settings_fd
, &prefs
, sizeof(struct preferences
));
1225 rb
->close(settings_fd
);
1229 /* load default settings if there is no settings file */
1230 viewer_default_settings();
1233 rb
->memcpy(&old_prefs
, &prefs
, sizeof(struct preferences
));
1235 data
= (struct bookmark_file_data
*)buffer
; /* grab the text buffer */
1236 data
->bookmarked_files_count
= 0;
1238 /* read bookmarks if file exists */
1239 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_RDONLY
);
1240 if (settings_fd
>= 0)
1242 /* figure out how many items to read */
1243 rb
->read(settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1244 if (data
->bookmarked_files_count
> MAX_BOOKMARKED_FILES
)
1245 data
->bookmarked_files_count
= MAX_BOOKMARKED_FILES
;
1246 rb
->read(settings_fd
, data
->bookmarks
,
1247 sizeof(struct bookmarked_file_info
) * data
->bookmarked_files_count
);
1248 rb
->close(settings_fd
);
1252 screen_top_ptr
= buffer
;
1254 /* check if current file is in list */
1255 for (i
=0; i
< data
->bookmarked_files_count
; i
++)
1257 if (!rb
->strcmp(file_name
, data
->bookmarks
[i
].filename
))
1259 int screen_pos
= data
->bookmarks
[i
].file_position
+ data
->bookmarks
[i
].top_ptr_pos
;
1260 int screen_top
= screen_pos
% buffer_size
;
1261 file_pos
= screen_pos
- screen_top
;
1262 screen_top_ptr
= buffer
+ screen_top
;
1267 this_bookmark
.file_position
= file_pos
;
1268 this_bookmark
.top_ptr_pos
= screen_top_ptr
- buffer
;
1270 rb
->memset(&this_bookmark
.filename
[0],0,MAX_PATH
);
1271 rb
->strcpy(this_bookmark
.filename
,file_name
);
1273 /* prevent potential slot overflow */
1274 if (i
>= data
->bookmarked_files_count
)
1276 if (i
< MAX_BOOKMARKED_FILES
)
1277 data
->bookmarked_files_count
++;
1279 i
= MAX_BOOKMARKED_FILES
-1;
1282 /* write bookmark file with spare slot in first position
1283 to be filled in by viewer_save_settings */
1284 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1285 if (settings_fd
>=0 )
1288 rb
->write (settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1290 /* write the current bookmark */
1291 rb
->write (settings_fd
, &this_bookmark
, sizeof(struct bookmarked_file_info
));
1293 /* write everything that was before this bookmark */
1294 rb
->write (settings_fd
, data
->bookmarks
, sizeof(struct bookmarked_file_info
)*i
);
1296 rb
->close(settings_fd
);
1299 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1301 if (BUFFER_OOB(screen_top_ptr
))
1303 screen_top_ptr
= buffer
;
1306 fill_buffer(file_pos
, buffer
, buffer_size
);
1308 /* remember the current position */
1309 start_position
= file_pos
+ screen_top_ptr
- buffer
;
1311 init_need_scrollbar();
1314 static void viewer_save_settings(void)/* same name as global, but not the same file.. */
1318 /* save the viewer settings if they have been changed */
1319 if (rb
->memcmp(&prefs
, &old_prefs
, sizeof(struct preferences
)))
1321 settings_fd
= rb
->creat(SETTINGS_FILE
); /* create the settings file */
1323 if (settings_fd
>= 0 )
1325 rb
->write (settings_fd
, &prefs
, sizeof(struct preferences
));
1326 rb
->close(settings_fd
);
1330 /* save the bookmark if the position has changed */
1331 if (file_pos
+ screen_top_ptr
- buffer
!= start_position
)
1333 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1335 if (settings_fd
>= 0 )
1337 struct bookmarked_file_info b
;
1338 b
.file_position
= file_pos
+ screen_top_ptr
- buffer
;
1339 b
.top_ptr_pos
= 0; /* this is only kept for legassy reasons */
1340 rb
->memset(&b
.filename
[0],0,MAX_PATH
);
1341 rb
->strcpy(b
.filename
,file_name
);
1342 rb
->lseek(settings_fd
,sizeof(signed int),SEEK_SET
);
1343 rb
->write (settings_fd
, &b
, sizeof(struct bookmarked_file_info
));
1344 rb
->close(settings_fd
);
1349 static void viewer_exit(void *parameter
)
1353 viewer_save_settings();
1357 static int col_limit(int col
)
1362 if (col
> max_line_len
- 2*glyph_width('o'))
1363 col
= max_line_len
- 2*glyph_width('o');
1368 /* settings helper functions */
1370 static bool encoding_setting(void)
1372 static struct opt_items names
[NUM_CODEPAGES
];
1375 for (idx
= 0; idx
< NUM_CODEPAGES
; idx
++)
1377 names
[idx
].string
= rb
->get_codepage_name(idx
);
1378 names
[idx
].voice_id
= -1;
1381 return rb
->set_option("Encoding", &prefs
.encoding
, INT
, names
,
1382 sizeof(names
) / sizeof(names
[0]), NULL
);
1385 static bool word_wrap_setting(void)
1387 static const struct opt_items names
[] = {
1389 {"Off (Chop Words)", -1},
1392 return rb
->set_option("Word Wrap", &prefs
.word_mode
, INT
,
1396 static bool line_mode_setting(void)
1398 static const struct opt_items names
[] = {
1401 {"Expand Lines", -1},
1402 #ifdef HAVE_LCD_BITMAP
1403 {"Reflow Lines", -1},
1407 return rb
->set_option("Line Mode", &prefs
.line_mode
, INT
, names
,
1408 sizeof(names
) / sizeof(names
[0]), NULL
);
1411 static bool view_mode_setting(void)
1413 static const struct opt_items names
[] = {
1414 {"No (Narrow)", -1},
1418 ret
= rb
->set_option("Wide View", &prefs
.view_mode
, INT
,
1420 if (prefs
.view_mode
== NARROW
)
1425 static bool scroll_mode_setting(void)
1427 static const struct opt_items names
[] = {
1428 {"Scroll by Page", -1},
1429 {"Scroll by Line", -1},
1432 return rb
->set_option("Scroll Mode", &prefs
.scroll_mode
, INT
,
1436 #ifdef HAVE_LCD_BITMAP
1437 static bool page_mode_setting(void)
1439 static const struct opt_items names
[] = {
1444 return rb
->set_option("Overlap Pages", &prefs
.page_mode
, INT
,
1448 static bool scrollbar_setting(void)
1450 static const struct opt_items names
[] = {
1455 return rb
->set_option("Show Scrollbar", &prefs
.scrollbar_mode
, INT
,
1460 static bool autoscroll_speed_setting(void)
1462 return rb
->set_int("Auto-scroll Speed", "", UNIT_INT
,
1463 &prefs
.autoscroll_speed
, NULL
, 1, 1, 10, NULL
);
1466 MENUITEM_FUNCTION(encoding_item
, 0, "Encoding", encoding_setting
,
1467 NULL
, NULL
, Icon_NOICON
);
1468 MENUITEM_FUNCTION(word_wrap_item
, 0, "Word Wrap", word_wrap_setting
,
1469 NULL
, NULL
, Icon_NOICON
);
1470 MENUITEM_FUNCTION(line_mode_item
, 0, "Line Mode", line_mode_setting
,
1471 NULL
, NULL
, Icon_NOICON
);
1472 MENUITEM_FUNCTION(view_mode_item
, 0, "Wide View", view_mode_setting
,
1473 NULL
, NULL
, Icon_NOICON
);
1474 #ifdef HAVE_LCD_BITMAP
1475 MENUITEM_FUNCTION(scrollbar_item
, 0, "Show Scrollbar", scrollbar_setting
,
1476 NULL
, NULL
, Icon_NOICON
);
1477 MENUITEM_FUNCTION(page_mode_item
, 0, "Overlap Pages", page_mode_setting
,
1478 NULL
, NULL
, Icon_NOICON
);
1480 MENUITEM_FUNCTION(scroll_mode_item
, 0, "Scroll Mode", scroll_mode_setting
,
1481 NULL
, NULL
, Icon_NOICON
);
1482 MENUITEM_FUNCTION(autoscroll_speed_item
, 0, "Auto-Scroll Speed",
1483 autoscroll_speed_setting
, NULL
, NULL
, Icon_NOICON
);
1484 MAKE_MENU(option_menu
, "Viewer Options", NULL
, Icon_NOICON
,
1485 &encoding_item
, &word_wrap_item
, &line_mode_item
, &view_mode_item
,
1486 #ifdef HAVE_LCD_BITMAP
1487 &scrollbar_item
, &page_mode_item
,
1489 &scroll_mode_item
, &autoscroll_speed_item
);
1491 static bool viewer_options_menu(void)
1494 result
= (rb
->do_menu(&option_menu
, NULL
, NULL
, false) == MENU_ATTACHED_USB
);
1496 #ifdef HAVE_LCD_BITMAP
1497 /* Show-scrollbar mode for current view-width mode */
1498 init_need_scrollbar();
1503 static void viewer_menu(void)
1506 MENUITEM_STRINGLIST(menu
, "Viewer Menu", NULL
,
1507 "Return", "Viewer Options",
1508 "Show Playback Menu", "Quit");
1510 result
= rb
->do_menu(&menu
, NULL
, NULL
, false);
1513 case 0: /* return */
1515 case 1: /* change settings */
1516 done
= viewer_options_menu();
1518 case 2: /* playback control */
1519 playback_control(NULL
);
1529 enum plugin_status
plugin_start(const void* file
)
1532 int lastbutton
= BUTTON_NONE
;
1533 bool autoscroll
= false;
1536 old_tick
= *rb
->current_tick
;
1538 /* get the plugin buffer */
1539 buffer
= rb
->plugin_get_buffer((size_t *)&buffer_size
);
1542 return PLUGIN_ERROR
;
1547 rb
->splash(HZ
, "Error opening file.");
1548 return PLUGIN_ERROR
;
1551 viewer_load_settings(); /* load the preferences and bookmark */
1554 rb
->lcd_set_backdrop(NULL
);
1563 if(old_tick
<= *rb
->current_tick
- (110-prefs
.autoscroll_speed
*10))
1565 viewer_scroll_down();
1567 old_tick
= *rb
->current_tick
;
1571 button
= rb
->button_get_w_tmo(HZ
/10);
1577 case VIEWER_AUTOSCROLL
:
1578 #ifdef VIEWER_AUTOSCROLL_PRE
1579 if (lastbutton
!= VIEWER_AUTOSCROLL_PRE
)
1582 autoscroll
= !autoscroll
;
1585 case VIEWER_PAGE_UP
:
1586 case VIEWER_PAGE_UP
| BUTTON_REPEAT
:
1587 if (prefs
.scroll_mode
== PAGE
)
1590 #ifdef HAVE_LCD_BITMAP
1591 for (i
= prefs
.page_mode
==OVERLAP
? 1:0; i
< display_lines
; i
++)
1593 for (i
= 0; i
< display_lines
; i
++)
1599 old_tick
= *rb
->current_tick
;
1603 case VIEWER_PAGE_DOWN
:
1604 case VIEWER_PAGE_DOWN
| BUTTON_REPEAT
:
1605 if (prefs
.scroll_mode
== PAGE
)
1608 if (next_screen_ptr
!= NULL
)
1609 screen_top_ptr
= next_screen_to_draw_ptr
;
1612 viewer_scroll_down();
1613 old_tick
= *rb
->current_tick
;
1617 case VIEWER_SCREEN_LEFT
:
1618 case VIEWER_SCREEN_LEFT
| BUTTON_REPEAT
:
1619 if (prefs
.view_mode
== WIDE
) {
1621 col
-= draw_columns
;
1622 col
= col_limit(col
);
1624 else { /* prefs.view_mode == NARROW */
1632 case VIEWER_SCREEN_RIGHT
:
1633 case VIEWER_SCREEN_RIGHT
| BUTTON_REPEAT
:
1634 if (prefs
.view_mode
== WIDE
) {
1636 col
+= draw_columns
;
1637 col
= col_limit(col
);
1639 else { /* prefs.view_mode == NARROW */
1640 /* Bottom of file */
1647 #ifdef VIEWER_LINE_UP
1648 case VIEWER_LINE_UP
:
1649 case VIEWER_LINE_UP
| BUTTON_REPEAT
:
1650 /* Scroll up one line */
1652 old_tick
= *rb
->current_tick
;
1656 case VIEWER_LINE_DOWN
:
1657 case VIEWER_LINE_DOWN
| BUTTON_REPEAT
:
1658 /* Scroll down one line */
1659 if (next_screen_ptr
!= NULL
)
1660 screen_top_ptr
= next_line_ptr
;
1661 old_tick
= *rb
->current_tick
;
1665 #ifdef VIEWER_COLUMN_LEFT
1666 case VIEWER_COLUMN_LEFT
:
1667 case VIEWER_COLUMN_LEFT
| BUTTON_REPEAT
:
1668 if (prefs
.view_mode
== WIDE
) {
1669 /* Scroll left one column */
1670 col
-= glyph_width('o');
1671 col
= col_limit(col
);
1676 case VIEWER_COLUMN_RIGHT
:
1677 case VIEWER_COLUMN_RIGHT
| BUTTON_REPEAT
:
1678 if (prefs
.view_mode
== WIDE
) {
1679 /* Scroll right one column */
1680 col
+= glyph_width('o');
1681 col
= col_limit(col
);
1687 #ifdef VIEWER_RC_QUIT
1688 case VIEWER_RC_QUIT
:
1696 if (rb
->default_event_handler_ex(button
, viewer_exit
, NULL
)
1697 == SYS_USB_CONNECTED
)
1698 return PLUGIN_USB_CONNECTED
;
1701 if (button
!= BUTTON_NONE
)
1703 lastbutton
= button
;