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 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
333 #error No keymap defined!
336 #ifdef HAVE_TOUCHSCREEN
338 #define VIEWER_QUIT BUTTON_TOPLEFT
340 #ifndef VIEWER_PAGE_UP
341 #define VIEWER_PAGE_UP BUTTON_TOPMIDDLE
343 #ifndef VIEWER_PAGE_DOWN
344 #define VIEWER_PAGE_DOWN BUTTON_BOTTOMMIDDLE
346 #ifndef VIEWER_SCREEN_LEFT
347 #define VIEWER_SCREEN_LEFT BUTTON_MIDLEFT
349 #ifndef VIEWER_SCREEN_RIGHT
350 #define VIEWER_SCREEN_RIGHT BUTTON_MIDRIGHT
353 #define VIEWER_MENU BUTTON_TOPRIGHT
355 #ifndef VIEWER_AUTOSCROLL
356 #define VIEWER_AUTOSCROLL BUTTON_CENTER
360 /* stuff for the bookmarking */
361 struct bookmarked_file_info
{
364 char filename
[MAX_PATH
];
367 struct bookmark_file_data
{
368 signed int bookmarked_files_count
;
369 struct bookmarked_file_info bookmarks
[];
382 REFLOW
, /* won't be set on charcell LCD, must be last */
390 enum codepages encoding
;
392 #ifdef HAVE_LCD_BITMAP
403 #endif /* HAVE_LCD_BITMAP */
410 int autoscroll_speed
;
414 struct preferences prefs
;
415 struct preferences old_prefs
;
417 static unsigned char *buffer
;
418 static long buffer_size
;
419 static unsigned char line_break
[] = {0,0x20,9,0xB,0xC,'-'};
420 static int display_columns
; /* number of (pixel) columns on the display */
421 static int display_lines
; /* number of lines on the display */
422 static int draw_columns
; /* number of (pixel) columns available for text */
423 static int par_indent_spaces
; /* number of spaces to indent first paragraph */
425 static const char *file_name
;
426 static long file_size
;
427 static long start_position
; /* position in the file after the viewer is started */
428 static bool mac_text
;
429 static long file_pos
; /* Position of the top of the buffer in the file */
430 static unsigned char *buffer_end
; /*Set to BUFFER_END() when file_pos changes*/
431 static int max_line_len
;
432 static unsigned char *screen_top_ptr
;
433 static unsigned char *next_screen_ptr
;
434 static unsigned char *next_screen_to_draw_ptr
;
435 static unsigned char *next_line_ptr
;
436 #ifdef HAVE_LCD_BITMAP
437 static struct font
*pf
;
441 int glyph_width(int ch
)
446 #ifdef HAVE_LCD_BITMAP
447 return rb
->font_get_width(pf
, ch
);
453 unsigned char* get_ucs(const unsigned char* str
, unsigned short* ch
)
455 unsigned char utf8_tmp
[6];
458 if (prefs
.encoding
== UTF_8
)
459 return (unsigned char*)rb
->utf8decode(str
, ch
);
461 count
= BUFFER_OOB(str
+2)? 1:2;
462 rb
->iso_decode(str
, utf8_tmp
, prefs
.encoding
, count
);
463 rb
->utf8decode(utf8_tmp
, ch
);
465 #ifdef HAVE_LCD_BITMAP
466 if ((prefs
.encoding
== SJIS
&& *str
> 0xA0 && *str
< 0xE0) || prefs
.encoding
< SJIS
)
467 return (unsigned char*)str
+1;
470 return (unsigned char*)str
+2;
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 static bool viewer_options_menu(void)
1456 static const struct menu_item items
[] = {
1457 {"Encoding", encoding_setting
},
1458 {"Word Wrap", word_wrap_setting
},
1459 {"Line Mode", line_mode_setting
},
1460 {"Wide View", view_mode_setting
},
1461 #ifdef HAVE_LCD_BITMAP
1462 {"Show Scrollbar", scrollbar_setting
},
1463 {"Overlap Pages", page_mode_setting
},
1465 {"Scroll Mode", scroll_mode_setting
},
1466 {"Auto-Scroll Speed", autoscroll_speed_setting
},
1468 m
= menu_init(items
, sizeof(items
) / sizeof(*items
),
1469 NULL
, NULL
, NULL
, NULL
);
1471 result
= menu_run(m
);
1473 #ifdef HAVE_LCD_BITMAP
1475 /* Show-scrollbar mode for current view-width mode */
1476 init_need_scrollbar();
1481 static void viewer_menu(void)
1485 static const struct menu_item items
[] = {
1487 {"Viewer Options", NULL
},
1488 {"Show Playback Menu", NULL
},
1492 m
= menu_init(items
, sizeof(items
) / sizeof(*items
), NULL
, NULL
, NULL
, NULL
);
1493 result
=menu_show(m
);
1501 case 1: /* change settings */
1502 done
= viewer_options_menu();
1504 case 2: /* playback control */
1505 playback_control(NULL
);
1507 case 3: /* return */
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
;