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_POWER
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
318 #error No keymap defined!
321 #ifdef HAVE_TOUCHSCREEN
323 #define VIEWER_QUIT BUTTON_TOPLEFT
325 #ifndef VIEWER_PAGE_UP
326 #define VIEWER_PAGE_UP BUTTON_TOPMIDDLE
328 #ifndef VIEWER_PAGE_DOWN
329 #define VIEWER_PAGE_DOWN BUTTON_BOTTOMMIDDLE
331 #ifndef VIEWER_SCREEN_LEFT
332 #define VIEWER_SCREEN_LEFT BUTTON_MIDLEFT
334 #ifndef VIEWER_SCREEN_RIGHT
335 #define VIEWER_SCREEN_RIGHT BUTTON_MIDRIGHT
338 #define VIEWER_MENU BUTTON_TOPRIGHT
340 #ifndef VIEWER_AUTOSCROLL
341 #define VIEWER_AUTOSCROLL BUTTON_CENTER
345 /* stuff for the bookmarking */
346 struct bookmarked_file_info
{
349 char filename
[MAX_PATH
];
352 struct bookmark_file_data
{
353 signed int bookmarked_files_count
;
354 struct bookmarked_file_info bookmarks
[];
367 REFLOW
, /* won't be set on charcell LCD, must be last */
375 enum codepages encoding
;
377 #ifdef HAVE_LCD_BITMAP
388 #endif /* HAVE_LCD_BITMAP */
395 int autoscroll_speed
;
399 struct preferences prefs
;
400 struct preferences old_prefs
;
402 static unsigned char *buffer
;
403 static long buffer_size
;
404 static unsigned char line_break
[] = {0,0x20,9,0xB,0xC,'-'};
405 static int display_columns
; /* number of (pixel) columns on the display */
406 static int display_lines
; /* number of lines on the display */
407 static int draw_columns
; /* number of (pixel) columns available for text */
408 static int par_indent_spaces
; /* number of spaces to indent first paragraph */
410 static const char *file_name
;
411 static long file_size
;
412 static long start_position
; /* position in the file after the viewer is started */
413 static bool mac_text
;
414 static long file_pos
; /* Position of the top of the buffer in the file */
415 static unsigned char *buffer_end
; /*Set to BUFFER_END() when file_pos changes*/
416 static int max_line_len
;
417 static unsigned char *screen_top_ptr
;
418 static unsigned char *next_screen_ptr
;
419 static unsigned char *next_screen_to_draw_ptr
;
420 static unsigned char *next_line_ptr
;
421 static const struct plugin_api
* rb
;
422 #ifdef HAVE_LCD_BITMAP
423 static struct font
*pf
;
427 int glyph_width(int ch
)
432 #ifdef HAVE_LCD_BITMAP
433 return rb
->font_get_width(pf
, ch
);
439 unsigned char* get_ucs(const unsigned char* str
, unsigned short* ch
)
441 unsigned char utf8_tmp
[6];
444 if (prefs
.encoding
== UTF_8
)
445 return (unsigned char*)rb
->utf8decode(str
, ch
);
447 count
= BUFFER_OOB(str
+2)? 1:2;
448 rb
->iso_decode(str
, utf8_tmp
, prefs
.encoding
, count
);
449 rb
->utf8decode(utf8_tmp
, ch
);
451 #ifdef HAVE_LCD_BITMAP
452 if ((prefs
.encoding
== SJIS
&& *str
> 0xA0 && *str
< 0xE0) || prefs
.encoding
< SJIS
)
453 return (unsigned char*)str
+1;
456 return (unsigned char*)str
+2;
462 #define ADVANCE_COUNTERS(c) { width += glyph_width(c); k++; }
463 #define LINE_IS_FULL ((k>=MAX_COLUMNS-1) ||( width >= draw_columns))
464 #define LINE_IS_NOT_FULL ((k<MAX_COLUMNS-1) &&( width < draw_columns))
465 static unsigned char* crop_at_width(const unsigned char* p
)
469 const unsigned char *oldp
= p
;
473 while (LINE_IS_NOT_FULL
) {
476 ADVANCE_COUNTERS(ch
);
479 return (unsigned char*)oldp
;
482 static unsigned char* find_first_feed(const unsigned char* p
, int size
)
486 for (i
=0; i
< size
; i
++)
488 return (unsigned char*) p
+i
;
493 static unsigned char* find_last_feed(const unsigned char* p
, int size
)
497 for (i
=size
-1; i
>=0; i
--)
499 return (unsigned char*) p
+i
;
504 static unsigned char* find_last_space(const unsigned char* p
, int size
)
508 k
= (prefs
.line_mode
==JOIN
) || (prefs
.line_mode
==REFLOW
) ? 0:1;
510 if (!BUFFER_OOB(&p
[size
]))
511 for (j
=k
; j
< ((int) sizeof(line_break
)) - 1; j
++)
512 if (p
[size
] == line_break
[j
])
513 return (unsigned char*) p
+size
;
515 for (i
=size
-1; i
>=0; i
--)
516 for (j
=k
; j
< (int) sizeof(line_break
); j
++)
518 if (!((p
[i
] == '-') && (prefs
.word_mode
== WRAP
)))
519 if (p
[i
] == line_break
[j
])
520 return (unsigned char*) p
+i
;
526 static unsigned char* find_next_line(const unsigned char* cur_line
, bool *is_short
)
528 const unsigned char *next_line
= NULL
;
529 int size
, i
, j
, k
, width
, search_len
, spaces
, newlines
;
533 if (is_short
!= NULL
)
536 if BUFFER_OOB(cur_line
)
539 if (prefs
.view_mode
== WIDE
) {
540 search_len
= MAX_WIDTH
;
542 else { /* prefs.view_mode == NARROW */
543 search_len
= crop_at_width(cur_line
) - cur_line
;
546 size
= BUFFER_OOB(cur_line
+search_len
) ? buffer_end
-cur_line
: search_len
;
548 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
)) {
549 /* Need to scan ahead and possibly increase search_len and size,
550 or possibly set next_line at second hard return in a row. */
553 for (j
=k
=width
=spaces
=newlines
=0; ; j
++) {
554 if (BUFFER_OOB(cur_line
+j
))
557 size
= search_len
= j
;
564 if (prefs
.line_mode
== REFLOW
) {
567 next_line
= cur_line
+ size
;
568 return (unsigned char*) next_line
;
570 if (j
==0) /* i=1 is intentional */
571 for (i
=0; i
<par_indent_spaces
; i
++)
572 ADVANCE_COUNTERS(' ');
574 if (!first_chars
) spaces
++;
580 next_line
= cur_line
+ size
- spaces
;
581 if (next_line
!= cur_line
)
582 return (unsigned char*) next_line
;
588 if (BUFFER_OOB(cur_line
+size
) || size
> 2*search_len
)
591 spaces
= first_chars
? 0:1;
595 if (prefs
.line_mode
==JOIN
|| newlines
>0) {
598 ADVANCE_COUNTERS(' ');
600 size
= search_len
= j
;
606 /* REFLOW, multiple spaces between words: count only
607 * one. If more are needed, they will be added
611 ADVANCE_COUNTERS(' ');
613 size
= search_len
= j
;
624 /* find first hard return */
625 next_line
= find_first_feed(cur_line
, size
);
628 if (next_line
== NULL
)
629 if (size
== search_len
) {
630 if (prefs
.word_mode
== WRAP
) /* Find last space */
631 next_line
= find_last_space(cur_line
, size
);
633 if (next_line
== NULL
)
634 next_line
= crop_at_width(cur_line
);
636 if (prefs
.word_mode
== WRAP
)
638 i
<WRAP_TRIM
&& isspace(next_line
[0]) && !BUFFER_OOB(next_line
);
643 if (prefs
.line_mode
== EXPAND
)
644 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
645 if (next_line
[0] == 0)
646 if (next_line
!= cur_line
)
647 return (unsigned char*) next_line
;
649 /* If next_line is pointing to a zero, increment it; i.e.,
650 leave the terminator at the end of cur_line. If pointing
651 to a hyphen, increment only if there is room to display
652 the hyphen on current line (won't apply in WIDE mode,
653 since it's guarenteed there won't be room). */
654 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
655 if (next_line
[0] == 0)/* ||
656 (next_line[0] == '-' && next_line-cur_line < draw_columns)) */
659 if (BUFFER_OOB(next_line
))
665 return (unsigned char*) next_line
;
668 static unsigned char* find_prev_line(const unsigned char* cur_line
)
670 const unsigned char *prev_line
= NULL
;
671 const unsigned char *p
;
673 if BUFFER_OOB(cur_line
)
676 /* To wrap consistently at the same places, we must
677 start with a known hard return, then work downwards.
678 We can either search backwards for a hard return,
679 or simply start wrapping downwards from top of buffer.
680 If current line is not near top of buffer, this is
681 a file with long lines (paragraphs). We would need to
682 read earlier sectors before we could decide how to
683 properly wrap the lines above the current line, but
684 it probably is not worth the disk access. Instead,
685 start with top of buffer and wrap down from there.
686 This may result in some lines wrapping at different
687 points from where they wrap when scrolling down.
688 If buffer is at top of file, start at top of buffer. */
690 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
))
691 prev_line
= p
= NULL
;
693 prev_line
= p
= find_last_feed(buffer
, cur_line
-buffer
-1);
694 /* Null means no line feeds in buffer above current line. */
696 if (prev_line
== NULL
)
697 if (BUFFER_BOF() || cur_line
- buffer
> READ_PREV_ZONE
)
698 prev_line
= p
= buffer
;
699 /* (else return NULL and read previous block) */
701 /* Wrap downwards until too far, then use the one before. */
702 while (p
< cur_line
&& p
!= NULL
) {
704 p
= find_next_line(prev_line
, NULL
);
707 if (BUFFER_OOB(prev_line
))
710 return (unsigned char*) prev_line
;
713 static void fill_buffer(long pos
, unsigned char* buf
, unsigned size
)
715 /* Read from file and preprocess the data */
716 /* To minimize disk access, always read on sector boundaries */
718 bool found_CR
= false;
720 rb
->lseek(fd
, pos
, SEEK_SET
);
721 numread
= rb
->read(fd
, buf
, size
);
722 rb
->button_clear_queue(); /* clear button queue */
724 for(i
= 0; i
< numread
; i
++) {
741 case 0: /* No break between case 0 and default, intentionally */
754 static int read_and_synch(int direction
)
756 /* Read next (or prev) block, and reposition global pointers. */
757 /* direction: 1 for down (i.e., further into file), -1 for up */
758 int move_size
, move_vector
, offset
;
759 unsigned char *fill_buf
;
761 if (direction
== -1) /* up */ {
762 move_size
= SMALL_BLOCK_SIZE
;
764 fill_buf
= TOP_SECTOR
;
765 rb
->memcpy(BOTTOM_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
766 rb
->memcpy(MID_SECTOR
, TOP_SECTOR
, SMALL_BLOCK_SIZE
);
769 if (prefs
.view_mode
== WIDE
) {
770 /* WIDE mode needs more buffer so we have to read smaller blocks */
771 move_size
= SMALL_BLOCK_SIZE
;
772 offset
= LARGE_BLOCK_SIZE
;
773 fill_buf
= BOTTOM_SECTOR
;
774 rb
->memcpy(TOP_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
775 rb
->memcpy(MID_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
778 move_size
= LARGE_BLOCK_SIZE
;
779 offset
= SMALL_BLOCK_SIZE
;
780 fill_buf
= MID_SECTOR
;
781 rb
->memcpy(TOP_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
784 move_vector
= direction
* move_size
;
785 screen_top_ptr
-= move_vector
;
786 file_pos
+= move_vector
;
787 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
788 fill_buffer(file_pos
+ offset
, fill_buf
, move_size
);
792 static void viewer_scroll_up(void)
796 p
= find_prev_line(screen_top_ptr
);
797 if (p
== NULL
&& !BUFFER_BOF()) {
799 p
= find_prev_line(screen_top_ptr
);
805 static void viewer_scroll_down(void)
807 if (next_screen_ptr
!= NULL
)
808 screen_top_ptr
= next_line_ptr
;
811 #ifdef HAVE_LCD_BITMAP
812 static void viewer_scrollbar(void) {
813 int items
, min_shown
, max_shown
;
815 items
= (int) file_size
; /* (SH1 int is same as long) */
816 min_shown
= (int) file_pos
+ (screen_top_ptr
- buffer
);
818 if (next_screen_ptr
== NULL
)
821 max_shown
= min_shown
+ (next_screen_ptr
- screen_top_ptr
);
823 rb
->gui_scrollbar_draw(rb
->screens
[SCREEN_MAIN
],0, 0, SCROLLBAR_WIDTH
-1,
824 LCD_HEIGHT
, items
, min_shown
, max_shown
, VERTICAL
);
828 static void viewer_draw(int col
)
830 int i
, j
, k
, line_len
, line_width
, resynch_move
, spaces
, left_col
=0;
831 int width
, extra_spaces
, indent_spaces
, spaces_per_word
;
832 bool multiple_spacing
, line_is_short
;
834 unsigned char *str
, *oldstr
;
835 unsigned char *line_begin
;
836 unsigned char *line_end
;
838 unsigned char scratch_buffer
[MAX_COLUMNS
+ 1];
839 unsigned char utf8_buffer
[MAX_COLUMNS
*4 + 1];
840 unsigned char *endptr
;
842 /* If col==-1 do all calculations but don't display */
844 #ifdef HAVE_LCD_BITMAP
845 left_col
= prefs
.need_scrollbar
? SCROLLBAR_WIDTH
:0;
849 rb
->lcd_clear_display();
852 line_begin
= line_end
= screen_top_ptr
;
854 for (i
= 0; i
< display_lines
; i
++) {
855 if (BUFFER_OOB(line_end
))
856 break; /* Happens after display last line at BUFFER_EOF() */
858 line_begin
= line_end
;
859 line_end
= find_next_line(line_begin
, &line_is_short
);
861 if (line_end
== NULL
) {
863 if (i
< display_lines
- 1 && !BUFFER_BOF()) {
865 rb
->lcd_clear_display();
867 for (; i
< display_lines
- 1; i
++)
870 line_begin
= line_end
= screen_top_ptr
;
875 line_end
= buffer_end
;
879 resynch_move
= read_and_synch(1); /* Read block & move ptrs */
880 line_begin
-= resynch_move
;
882 next_line_ptr
-= resynch_move
;
884 line_end
= find_next_line(line_begin
, NULL
);
885 if (line_end
== NULL
) /* Should not really happen */
889 line_len
= line_end
- line_begin
;
891 /* calculate line_len */
892 str
= oldstr
= line_begin
;
894 while (str
< line_end
) {
896 str
= crop_at_width(str
);
899 line_width
= j
*draw_columns
;
900 while (oldstr
< line_end
) {
901 oldstr
= get_ucs(oldstr
, &ch
);
902 line_width
+= glyph_width(ch
);
905 if (prefs
.line_mode
== JOIN
) {
906 if (line_begin
[0] == 0) {
908 if (prefs
.word_mode
== CHOP
)
913 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
914 if (k
== MAX_COLUMNS
)
924 scratch_buffer
[k
++] = ' ';
929 scratch_buffer
[k
++] = ' ';
930 if (k
== MAX_COLUMNS
- 1)
933 scratch_buffer
[k
++] = c
;
938 scratch_buffer
[k
] = 0;
939 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
940 prefs
.encoding
, draw_columns
/glyph_width('i'));
944 else if (prefs
.line_mode
== REFLOW
) {
945 if (line_begin
[0] == 0) {
947 if (prefs
.word_mode
== CHOP
)
954 if (!line_is_short
) {
955 multiple_spacing
= false;
957 for (str
= line_begin
; str
< line_end
; ) {
958 str
= get_ucs(str
, &ch
);
962 if ((str
== line_begin
) && (prefs
.word_mode
==WRAP
))
963 /* special case: indent the paragraph,
964 * don't count spaces */
965 indent_spaces
= par_indent_spaces
;
966 else if (!multiple_spacing
)
968 multiple_spacing
= true;
971 multiple_spacing
= false;
972 width
+= glyph_width(ch
);
976 if (multiple_spacing
) spaces
--;
979 /* total number of spaces to insert between words */
980 extra_spaces
= (draw_columns
-width
)/glyph_width(' ')
982 /* number of spaces between each word*/
983 spaces_per_word
= extra_spaces
/ spaces
;
984 /* number of words with n+1 spaces (to fill up) */
985 extra_spaces
= extra_spaces
% spaces
;
986 if (spaces_per_word
> 2) { /* too much spacing is awful */
990 } else { /* this doesn't matter much... no spaces anyway */
991 spaces_per_word
= extra_spaces
= 0;
993 } else { /* end of a paragraph: don't fill line */
998 multiple_spacing
= false;
999 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
1000 if (k
== MAX_COLUMNS
)
1007 if (j
==0 && prefs
.word_mode
==WRAP
) { /* indent paragraph */
1008 for (j
=0; j
<par_indent_spaces
; j
++)
1009 scratch_buffer
[k
++] = ' ';
1012 else if (!multiple_spacing
) {
1013 for (width
= spaces
<extra_spaces
? -1:0; width
< spaces_per_word
; width
++)
1014 scratch_buffer
[k
++] = ' ';
1017 multiple_spacing
= true;
1020 scratch_buffer
[k
++] = c
;
1021 multiple_spacing
= false;
1027 scratch_buffer
[k
] = 0;
1028 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
1029 prefs
.encoding
, k
-col
);
1033 else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */
1035 if (line_width
> col
) {
1036 str
= oldstr
= line_begin
;
1039 while( (width
<draw_columns
) && (oldstr
<line_end
) )
1041 oldstr
= get_ucs(oldstr
, &ch
);
1043 k
-= glyph_width(ch
);
1044 line_begin
= oldstr
;
1046 width
+= glyph_width(ch
);
1050 if(prefs
.view_mode
==WIDE
)
1051 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1052 prefs
.encoding
, oldstr
-line_begin
);
1054 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1055 prefs
.encoding
, line_end
-line_begin
);
1059 if (col
!= -1 && line_width
> col
)
1060 #ifdef HAVE_LCD_BITMAP
1061 rb
->lcd_putsxy(left_col
, i
*pf
->height
, utf8_buffer
);
1063 rb
->lcd_puts(left_col
, i
, utf8_buffer
);
1065 if (line_width
> max_line_len
)
1066 max_line_len
= line_width
;
1069 next_line_ptr
= line_end
;
1071 next_screen_ptr
= line_end
;
1072 if (BUFFER_OOB(next_screen_ptr
))
1073 next_screen_ptr
= NULL
;
1075 #ifdef HAVE_LCD_BITMAP
1076 next_screen_to_draw_ptr
= prefs
.page_mode
==OVERLAP
? line_begin
: next_screen_ptr
;
1078 if (prefs
.need_scrollbar
)
1081 next_screen_to_draw_ptr
= next_screen_ptr
;
1088 static void viewer_top(void)
1090 /* Read top of file into buffer
1091 and point screen pointer to top */
1095 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1096 fill_buffer(0, buffer
, buffer_size
);
1099 screen_top_ptr
= buffer
;
1102 static void viewer_bottom(void)
1104 /* Read bottom of file into buffer
1105 and point screen pointer to bottom */
1108 if (file_size
> buffer_size
) {
1109 /* Find last buffer in file, round up to next sector boundary */
1110 last_sectors
= file_size
- buffer_size
+ SMALL_BLOCK_SIZE
;
1111 last_sectors
/= SMALL_BLOCK_SIZE
;
1112 last_sectors
*= SMALL_BLOCK_SIZE
;
1118 if (file_pos
!= last_sectors
)
1120 file_pos
= last_sectors
;
1121 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1122 fill_buffer(last_sectors
, buffer
, buffer_size
);
1125 screen_top_ptr
= buffer_end
-1;
1128 #ifdef HAVE_LCD_BITMAP
1129 static void init_need_scrollbar(void) {
1130 /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
1131 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
1133 prefs
.need_scrollbar
= NEED_SCROLLBAR();
1134 draw_columns
= prefs
.need_scrollbar
? display_columns
-SCROLLBAR_WIDTH
: display_columns
;
1135 par_indent_spaces
= draw_columns
/(5*glyph_width(' '));
1138 #define init_need_scrollbar()
1141 static bool viewer_init(void)
1143 #ifdef HAVE_LCD_BITMAP
1145 pf
= rb
->font_get(FONT_UI
);
1147 display_lines
= LCD_HEIGHT
/ pf
->height
;
1148 draw_columns
= display_columns
= LCD_WIDTH
;
1150 /* REAL fixed pitch :) all chars use up 1 cell */
1152 draw_columns
= display_columns
= 11;
1153 par_indent_spaces
= 2;
1156 fd
= rb
->open(file_name
, O_RDONLY
);
1160 file_size
= rb
->filesize(fd
);
1164 /* Init mac_text value used in processing buffer */
1170 static void viewer_default_settings(void)
1172 prefs
.word_mode
= WRAP
;
1173 prefs
.line_mode
= NORMAL
;
1174 prefs
.view_mode
= NARROW
;
1175 prefs
.scroll_mode
= PAGE
;
1176 #ifdef HAVE_LCD_BITMAP
1177 prefs
.page_mode
= NO_OVERLAP
;
1178 prefs
.scrollbar_mode
= SB_OFF
;
1180 prefs
.autoscroll_speed
= 1;
1181 /* Set codepage to system default */
1182 prefs
.encoding
= rb
->global_settings
->default_codepage
;
1185 static void viewer_load_settings(void) /* same name as global, but not the same file.. */
1188 struct bookmark_file_data
*data
;
1189 struct bookmarked_file_info this_bookmark
;
1191 /* read settings file */
1192 settings_fd
=rb
->open(SETTINGS_FILE
, O_RDONLY
);
1193 if ((settings_fd
>= 0) && (rb
->filesize(settings_fd
) == sizeof(struct preferences
)))
1195 rb
->read(settings_fd
, &prefs
, sizeof(struct preferences
));
1196 rb
->close(settings_fd
);
1200 /* load default settings if there is no settings file */
1201 viewer_default_settings();
1204 rb
->memcpy(&old_prefs
, &prefs
, sizeof(struct preferences
));
1206 data
= (struct bookmark_file_data
*)buffer
; /* grab the text buffer */
1207 data
->bookmarked_files_count
= 0;
1209 /* read bookmarks if file exists */
1210 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_RDONLY
);
1211 if (settings_fd
>= 0)
1213 /* figure out how many items to read */
1214 rb
->read(settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1215 if (data
->bookmarked_files_count
> MAX_BOOKMARKED_FILES
)
1216 data
->bookmarked_files_count
= MAX_BOOKMARKED_FILES
;
1217 rb
->read(settings_fd
, data
->bookmarks
,
1218 sizeof(struct bookmarked_file_info
) * data
->bookmarked_files_count
);
1219 rb
->close(settings_fd
);
1223 screen_top_ptr
= buffer
;
1225 /* check if current file is in list */
1226 for (i
=0; i
< data
->bookmarked_files_count
; i
++)
1228 if (!rb
->strcmp(file_name
, data
->bookmarks
[i
].filename
))
1230 int screen_pos
= data
->bookmarks
[i
].file_position
+ data
->bookmarks
[i
].top_ptr_pos
;
1231 int screen_top
= screen_pos
% buffer_size
;
1232 file_pos
= screen_pos
- screen_top
;
1233 screen_top_ptr
= buffer
+ screen_top
;
1238 this_bookmark
.file_position
= file_pos
;
1239 this_bookmark
.top_ptr_pos
= screen_top_ptr
- buffer
;
1241 rb
->memset(&this_bookmark
.filename
[0],0,MAX_PATH
);
1242 rb
->strcpy(this_bookmark
.filename
,file_name
);
1244 /* prevent potential slot overflow */
1245 if (i
>= data
->bookmarked_files_count
)
1247 if (i
< MAX_BOOKMARKED_FILES
)
1248 data
->bookmarked_files_count
++;
1250 i
= MAX_BOOKMARKED_FILES
-1;
1253 /* write bookmark file with spare slot in first position
1254 to be filled in by viewer_save_settings */
1255 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1256 if (settings_fd
>=0 )
1259 rb
->write (settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1261 /* write the current bookmark */
1262 rb
->write (settings_fd
, &this_bookmark
, sizeof(struct bookmarked_file_info
));
1264 /* write everything that was before this bookmark */
1265 rb
->write (settings_fd
, data
->bookmarks
, sizeof(struct bookmarked_file_info
)*i
);
1267 rb
->close(settings_fd
);
1270 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1272 if (BUFFER_OOB(screen_top_ptr
))
1274 screen_top_ptr
= buffer
;
1277 fill_buffer(file_pos
, buffer
, buffer_size
);
1279 /* remember the current position */
1280 start_position
= file_pos
+ screen_top_ptr
- buffer
;
1282 init_need_scrollbar();
1285 static void viewer_save_settings(void)/* same name as global, but not the same file.. */
1289 /* save the viewer settings if they have been changed */
1290 if (rb
->memcmp(&prefs
, &old_prefs
, sizeof(struct preferences
)))
1292 settings_fd
= rb
->creat(SETTINGS_FILE
); /* create the settings file */
1294 if (settings_fd
>= 0 )
1296 rb
->write (settings_fd
, &prefs
, sizeof(struct preferences
));
1297 rb
->close(settings_fd
);
1301 /* save the bookmark if the position has changed */
1302 if (file_pos
+ screen_top_ptr
- buffer
!= start_position
)
1304 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1306 if (settings_fd
>= 0 )
1308 struct bookmarked_file_info b
;
1309 b
.file_position
= file_pos
+ screen_top_ptr
- buffer
;
1310 b
.top_ptr_pos
= 0; /* this is only kept for legassy reasons */
1311 rb
->memset(&b
.filename
[0],0,MAX_PATH
);
1312 rb
->strcpy(b
.filename
,file_name
);
1313 rb
->lseek(settings_fd
,sizeof(signed int),SEEK_SET
);
1314 rb
->write (settings_fd
, &b
, sizeof(struct bookmarked_file_info
));
1315 rb
->close(settings_fd
);
1320 static void viewer_exit(void *parameter
)
1324 viewer_save_settings();
1328 static int col_limit(int col
)
1333 if (col
> max_line_len
- 2*glyph_width('o'))
1334 col
= max_line_len
- 2*glyph_width('o');
1339 /* settings helper functions */
1341 static bool encoding_setting(void)
1343 static struct opt_items names
[NUM_CODEPAGES
];
1346 for (idx
= 0; idx
< NUM_CODEPAGES
; idx
++)
1348 names
[idx
].string
= rb
->get_codepage_name(idx
);
1349 names
[idx
].voice_id
= -1;
1352 return rb
->set_option("Encoding", &prefs
.encoding
, INT
, names
,
1353 sizeof(names
) / sizeof(names
[0]), NULL
);
1356 static bool word_wrap_setting(void)
1358 static const struct opt_items names
[] = {
1360 {"Off (Chop Words)", -1},
1363 return rb
->set_option("Word Wrap", &prefs
.word_mode
, INT
,
1367 static bool line_mode_setting(void)
1369 static const struct opt_items names
[] = {
1372 {"Expand Lines", -1},
1373 #ifdef HAVE_LCD_BITMAP
1374 {"Reflow Lines", -1},
1378 return rb
->set_option("Line Mode", &prefs
.line_mode
, INT
, names
,
1379 sizeof(names
) / sizeof(names
[0]), NULL
);
1382 static bool view_mode_setting(void)
1384 static const struct opt_items names
[] = {
1385 {"No (Narrow)", -1},
1389 ret
= rb
->set_option("Wide View", &prefs
.view_mode
, INT
,
1391 if (prefs
.view_mode
== NARROW
)
1396 static bool scroll_mode_setting(void)
1398 static const struct opt_items names
[] = {
1399 {"Scroll by Page", -1},
1400 {"Scroll by Line", -1},
1403 return rb
->set_option("Scroll Mode", &prefs
.scroll_mode
, INT
,
1407 #ifdef HAVE_LCD_BITMAP
1408 static bool page_mode_setting(void)
1410 static const struct opt_items names
[] = {
1415 return rb
->set_option("Overlap Pages", &prefs
.page_mode
, INT
,
1419 static bool scrollbar_setting(void)
1421 static const struct opt_items names
[] = {
1426 return rb
->set_option("Show Scrollbar", &prefs
.scrollbar_mode
, INT
,
1431 static bool autoscroll_speed_setting(void)
1433 return rb
->set_int("Auto-scroll Speed", "", UNIT_INT
,
1434 &prefs
.autoscroll_speed
, NULL
, 1, 1, 10, NULL
);
1437 static bool viewer_options_menu(void)
1442 static const struct menu_item items
[] = {
1443 {"Encoding", encoding_setting
},
1444 {"Word Wrap", word_wrap_setting
},
1445 {"Line Mode", line_mode_setting
},
1446 {"Wide View", view_mode_setting
},
1447 #ifdef HAVE_LCD_BITMAP
1448 {"Show Scrollbar", scrollbar_setting
},
1449 {"Overlap Pages", page_mode_setting
},
1451 {"Scroll Mode", scroll_mode_setting
},
1452 {"Auto-Scroll Speed", autoscroll_speed_setting
},
1454 m
= menu_init(rb
, items
, sizeof(items
) / sizeof(*items
),
1455 NULL
, NULL
, NULL
, NULL
);
1457 result
= menu_run(m
);
1459 #ifdef HAVE_LCD_BITMAP
1461 /* Show-scrollbar mode for current view-width mode */
1462 init_need_scrollbar();
1467 static void viewer_menu(void)
1471 static const struct menu_item items
[] = {
1473 {"Viewer Options", NULL
},
1474 {"Show Playback Menu", NULL
},
1478 m
= menu_init(rb
, items
, sizeof(items
) / sizeof(*items
), NULL
, NULL
, NULL
, NULL
);
1479 result
=menu_show(m
);
1487 case 1: /* change settings */
1488 done
= viewer_options_menu();
1490 case 2: /* playback control */
1491 playback_control(rb
, NULL
);
1493 case 3: /* return */
1500 enum plugin_status
plugin_start(const struct plugin_api
* api
, const void* file
)
1503 int lastbutton
= BUTTON_NONE
;
1504 bool autoscroll
= false;
1508 old_tick
= *rb
->current_tick
;
1510 /* get the plugin buffer */
1511 buffer
= rb
->plugin_get_buffer((size_t *)&buffer_size
);
1514 return PLUGIN_ERROR
;
1519 rb
->splash(HZ
, "Error opening file.");
1520 return PLUGIN_ERROR
;
1523 viewer_load_settings(); /* load the preferences and bookmark */
1526 rb
->lcd_set_backdrop(NULL
);
1535 if(old_tick
<= *rb
->current_tick
- (110-prefs
.autoscroll_speed
*10))
1537 viewer_scroll_down();
1539 old_tick
= *rb
->current_tick
;
1543 button
= rb
->button_get_w_tmo(HZ
/10);
1549 case VIEWER_AUTOSCROLL
:
1550 #ifdef VIEWER_AUTOSCROLL_PRE
1551 if (lastbutton
!= VIEWER_AUTOSCROLL_PRE
)
1554 autoscroll
= !autoscroll
;
1557 case VIEWER_PAGE_UP
:
1558 case VIEWER_PAGE_UP
| BUTTON_REPEAT
:
1559 if (prefs
.scroll_mode
== PAGE
)
1562 #ifdef HAVE_LCD_BITMAP
1563 for (i
= prefs
.page_mode
==OVERLAP
? 1:0; i
< display_lines
; i
++)
1565 for (i
= 0; i
< display_lines
; i
++)
1571 old_tick
= *rb
->current_tick
;
1575 case VIEWER_PAGE_DOWN
:
1576 case VIEWER_PAGE_DOWN
| BUTTON_REPEAT
:
1577 if (prefs
.scroll_mode
== PAGE
)
1580 if (next_screen_ptr
!= NULL
)
1581 screen_top_ptr
= next_screen_to_draw_ptr
;
1584 viewer_scroll_down();
1585 old_tick
= *rb
->current_tick
;
1589 case VIEWER_SCREEN_LEFT
:
1590 case VIEWER_SCREEN_LEFT
| BUTTON_REPEAT
:
1591 if (prefs
.view_mode
== WIDE
) {
1593 col
-= draw_columns
;
1594 col
= col_limit(col
);
1596 else { /* prefs.view_mode == NARROW */
1604 case VIEWER_SCREEN_RIGHT
:
1605 case VIEWER_SCREEN_RIGHT
| BUTTON_REPEAT
:
1606 if (prefs
.view_mode
== WIDE
) {
1608 col
+= draw_columns
;
1609 col
= col_limit(col
);
1611 else { /* prefs.view_mode == NARROW */
1612 /* Bottom of file */
1619 #ifdef VIEWER_LINE_UP
1620 case VIEWER_LINE_UP
:
1621 case VIEWER_LINE_UP
| BUTTON_REPEAT
:
1622 /* Scroll up one line */
1624 old_tick
= *rb
->current_tick
;
1628 case VIEWER_LINE_DOWN
:
1629 case VIEWER_LINE_DOWN
| BUTTON_REPEAT
:
1630 /* Scroll down one line */
1631 if (next_screen_ptr
!= NULL
)
1632 screen_top_ptr
= next_line_ptr
;
1633 old_tick
= *rb
->current_tick
;
1637 #ifdef VIEWER_COLUMN_LEFT
1638 case VIEWER_COLUMN_LEFT
:
1639 case VIEWER_COLUMN_LEFT
| BUTTON_REPEAT
:
1640 if (prefs
.view_mode
== WIDE
) {
1641 /* Scroll left one column */
1642 col
-= glyph_width('o');
1643 col
= col_limit(col
);
1648 case VIEWER_COLUMN_RIGHT
:
1649 case VIEWER_COLUMN_RIGHT
| BUTTON_REPEAT
:
1650 if (prefs
.view_mode
== WIDE
) {
1651 /* Scroll right one column */
1652 col
+= glyph_width('o');
1653 col
= col_limit(col
);
1659 #ifdef VIEWER_RC_QUIT
1660 case VIEWER_RC_QUIT
:
1668 if (rb
->default_event_handler_ex(button
, viewer_exit
, NULL
)
1669 == SYS_USB_CONNECTED
)
1670 return PLUGIN_USB_CONNECTED
;
1673 if (button
!= BUTTON_NONE
)
1675 lastbutton
= button
;