1 /***************************************************************************
4 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
11 * Copyright (C) 2002 Gilles Roux, 2003 Garrett Derner
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
24 #include "lib/playback_control.h"
28 #define SETTINGS_FILE VIEWERS_DIR "/viewer.dat" /* binary file, so dont use .cfg */
29 #define BOOKMARKS_FILE VIEWERS_DIR "/viewer_bookmarks.dat"
31 #define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */
32 #define MAX_COLUMNS 64 /* Max displayable string len (over-estimate) */
33 #define MAX_WIDTH 910 /* Max line length in WIDE mode */
34 #define READ_PREV_ZONE 910 /* Arbitrary number less than SMALL_BLOCK_SIZE */
35 #define SMALL_BLOCK_SIZE 0x1000 /* 4k: Smallest file chunk we will read */
36 #define LARGE_BLOCK_SIZE 0x2000 /* 8k: Preferable size of file chunk to read */
37 #define TOP_SECTOR buffer
38 #define MID_SECTOR (buffer + SMALL_BLOCK_SIZE)
39 #define BOTTOM_SECTOR (buffer + 2*(SMALL_BLOCK_SIZE))
40 #define SCROLLBAR_WIDTH 6
42 #define MAX_BOOKMARKED_FILES ((buffer_size/(signed)sizeof(struct bookmarked_file_info))-1)
44 /* Out-Of-Bounds test for any pointer to data in the buffer */
45 #define BUFFER_OOB(p) ((p) < buffer || (p) >= buffer_end)
47 /* Does the buffer contain the beginning of the file? */
48 #define BUFFER_BOF() (file_pos==0)
50 /* Does the buffer contain the end of the file? */
51 #define BUFFER_EOF() (file_size-file_pos <= buffer_size)
53 /* Formula for the endpoint address outside of buffer data */
54 #define BUFFER_END() \
55 ((BUFFER_EOF()) ? (file_size-file_pos+buffer) : (buffer+buffer_size))
57 /* Is the entire file being shown in one screen? */
58 #define ONE_SCREEN_FITS_ALL() \
59 (next_screen_ptr==NULL && screen_top_ptr==buffer && BUFFER_BOF())
61 /* Is a scrollbar called for on the current screen? */
62 #define NEED_SCROLLBAR() \
63 ((!(ONE_SCREEN_FITS_ALL())) && (prefs.scrollbar_mode==SB_ON))
65 /* variable button definitions */
68 #if CONFIG_KEYPAD == RECORDER_PAD
69 #define VIEWER_QUIT BUTTON_OFF
70 #define VIEWER_PAGE_UP BUTTON_UP
71 #define VIEWER_PAGE_DOWN BUTTON_DOWN
72 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
73 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
74 #define VIEWER_MENU BUTTON_F1
75 #define VIEWER_AUTOSCROLL BUTTON_PLAY
76 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
77 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
78 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
79 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
81 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
82 #define VIEWER_QUIT BUTTON_OFF
83 #define VIEWER_PAGE_UP BUTTON_UP
84 #define VIEWER_PAGE_DOWN BUTTON_DOWN
85 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
86 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
87 #define VIEWER_MENU BUTTON_F1
88 #define VIEWER_AUTOSCROLL BUTTON_SELECT
89 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
90 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
91 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
92 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
95 #elif CONFIG_KEYPAD == ONDIO_PAD
96 #define VIEWER_QUIT BUTTON_OFF
97 #define VIEWER_PAGE_UP BUTTON_UP
98 #define VIEWER_PAGE_DOWN BUTTON_DOWN
99 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
100 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
101 #define VIEWER_MENU (BUTTON_MENU|BUTTON_REPEAT)
102 #define VIEWER_AUTOSCROLL_PRE BUTTON_MENU
103 #define VIEWER_AUTOSCROLL (BUTTON_MENU|BUTTON_REL)
106 #elif CONFIG_KEYPAD == PLAYER_PAD
107 #define VIEWER_QUIT BUTTON_STOP
108 #define VIEWER_PAGE_UP BUTTON_LEFT
109 #define VIEWER_PAGE_DOWN BUTTON_RIGHT
110 #define VIEWER_SCREEN_LEFT (BUTTON_ON|BUTTON_LEFT)
111 #define VIEWER_SCREEN_RIGHT (BUTTON_ON|BUTTON_RIGHT)
112 #define VIEWER_MENU BUTTON_MENU
113 #define VIEWER_AUTOSCROLL BUTTON_PLAY
115 /* iRiver H1x0 && H3x0 keys */
116 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
117 (CONFIG_KEYPAD == IRIVER_H300_PAD)
118 #define VIEWER_QUIT BUTTON_OFF
119 #define VIEWER_PAGE_UP BUTTON_UP
120 #define VIEWER_PAGE_DOWN BUTTON_DOWN
121 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
122 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
123 #define VIEWER_MENU BUTTON_MODE
124 #define VIEWER_AUTOSCROLL BUTTON_SELECT
125 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
126 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
127 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
128 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
130 #define VIEWER_RC_QUIT BUTTON_RC_STOP
133 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
134 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
135 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
136 #define VIEWER_QUIT_PRE BUTTON_SELECT
137 #define VIEWER_QUIT (BUTTON_SELECT | BUTTON_MENU)
138 #define VIEWER_PAGE_UP BUTTON_SCROLL_BACK
139 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_FWD
140 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
141 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
142 #define VIEWER_MENU BUTTON_MENU
143 #define VIEWER_AUTOSCROLL BUTTON_PLAY
146 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
147 #define VIEWER_QUIT BUTTON_PLAY
148 #define VIEWER_PAGE_UP BUTTON_UP
149 #define VIEWER_PAGE_DOWN BUTTON_DOWN
150 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
151 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
152 #define VIEWER_MENU BUTTON_MODE
153 #define VIEWER_AUTOSCROLL BUTTON_SELECT
156 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
157 #define VIEWER_QUIT BUTTON_POWER
158 #define VIEWER_PAGE_UP BUTTON_UP
159 #define VIEWER_PAGE_DOWN BUTTON_DOWN
160 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
161 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
162 #define VIEWER_MENU BUTTON_SELECT
163 #define VIEWER_AUTOSCROLL BUTTON_PLAY
166 #elif CONFIG_KEYPAD == GIGABEAT_PAD
167 #define VIEWER_QUIT BUTTON_POWER
168 #define VIEWER_PAGE_UP BUTTON_UP
169 #define VIEWER_PAGE_DOWN BUTTON_DOWN
170 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
171 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
172 #define VIEWER_MENU BUTTON_MENU
173 #define VIEWER_AUTOSCROLL BUTTON_A
175 /* Sansa E200 keys */
176 #elif CONFIG_KEYPAD == SANSA_E200_PAD
177 #define VIEWER_QUIT BUTTON_POWER
178 #define VIEWER_PAGE_UP BUTTON_UP
179 #define VIEWER_PAGE_DOWN BUTTON_DOWN
180 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
181 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
182 #define VIEWER_MENU BUTTON_SELECT
183 #define VIEWER_AUTOSCROLL BUTTON_REC
184 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
185 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
187 /* Sansa Fuze keys */
188 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
189 #define VIEWER_QUIT (BUTTON_HOME|BUTTON_REPEAT)
190 #define VIEWER_PAGE_UP BUTTON_UP
191 #define VIEWER_PAGE_DOWN BUTTON_DOWN
192 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
193 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
194 #define VIEWER_MENU BUTTON_SELECT|BUTTON_REPEAT
195 #define VIEWER_AUTOSCROLL BUTTON_SELECT|BUTTON_DOWN
196 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
197 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
199 /* Sansa C200 keys */
200 #elif CONFIG_KEYPAD == SANSA_C200_PAD
201 #define VIEWER_QUIT BUTTON_POWER
202 #define VIEWER_PAGE_UP BUTTON_VOL_UP
203 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
204 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
205 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
206 #define VIEWER_MENU BUTTON_SELECT
207 #define VIEWER_AUTOSCROLL BUTTON_REC
208 #define VIEWER_LINE_UP BUTTON_UP
209 #define VIEWER_LINE_DOWN BUTTON_DOWN
211 /* Sansa Clip keys */
212 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
213 #define VIEWER_QUIT BUTTON_POWER
214 #define VIEWER_PAGE_UP BUTTON_VOL_UP
215 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
216 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
217 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
218 #define VIEWER_MENU BUTTON_SELECT
219 #define VIEWER_AUTOSCROLL BUTTON_HOME
220 #define VIEWER_LINE_UP BUTTON_UP
221 #define VIEWER_LINE_DOWN BUTTON_DOWN
223 /* Sansa M200 keys */
224 #elif CONFIG_KEYPAD == SANSA_M200_PAD
225 #define VIEWER_QUIT BUTTON_POWER
226 #define VIEWER_PAGE_UP BUTTON_VOL_UP
227 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
228 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
229 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
230 #define VIEWER_MENU (BUTTON_SELECT | BUTTON_UP)
231 #define VIEWER_AUTOSCROLL (BUTTON_SELECT | BUTTON_REL)
232 #define VIEWER_LINE_UP BUTTON_UP
233 #define VIEWER_LINE_DOWN BUTTON_DOWN
235 /* iriver H10 keys */
236 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
237 #define VIEWER_QUIT BUTTON_POWER
238 #define VIEWER_PAGE_UP BUTTON_SCROLL_UP
239 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_DOWN
240 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
241 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
242 #define VIEWER_MENU BUTTON_REW
243 #define VIEWER_AUTOSCROLL BUTTON_PLAY
246 #elif CONFIG_KEYPAD == MROBE500_PAD
247 #define VIEWER_QUIT BUTTON_POWER
248 #define VIEWER_PAGE_UP BUTTON_RC_PLAY
249 #define VIEWER_PAGE_DOWN BUTTON_RC_DOWN
250 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
251 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
252 #define VIEWER_MENU BUTTON_RC_HEART
253 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
256 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
257 #define VIEWER_QUIT BUTTON_BACK
258 #define VIEWER_PAGE_UP BUTTON_PREV
259 #define VIEWER_PAGE_DOWN BUTTON_NEXT
260 #define VIEWER_SCREEN_LEFT (BUTTON_PLAY | BUTTON_LEFT)
261 #define VIEWER_SCREEN_RIGHT (BUTTON_PLAY | BUTTON_RIGHT)
262 #define VIEWER_MENU BUTTON_MENU
263 #define VIEWER_AUTOSCROLL_PRE BUTTON_PLAY
264 #define VIEWER_AUTOSCROLL (BUTTON_PLAY|BUTTON_REL)
265 #define VIEWER_LINE_UP BUTTON_UP
266 #define VIEWER_LINE_DOWN BUTTON_DOWN
267 #define VIEWER_COLUMN_LEFT BUTTON_LEFT
268 #define VIEWER_COLUMN_RIGHT BUTTON_RIGHT
271 #elif CONFIG_KEYPAD == MROBE100_PAD
272 #define VIEWER_QUIT BUTTON_POWER
273 #define VIEWER_PAGE_UP BUTTON_UP
274 #define VIEWER_PAGE_DOWN BUTTON_DOWN
275 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
276 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
277 #define VIEWER_MENU BUTTON_MENU
278 #define VIEWER_AUTOSCROLL BUTTON_DISPLAY
281 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
282 #define VIEWER_QUIT BUTTON_RC_REC
283 #define VIEWER_PAGE_UP BUTTON_RC_VOL_UP
284 #define VIEWER_PAGE_DOWN BUTTON_RC_VOL_DOWN
285 #define VIEWER_SCREEN_LEFT BUTTON_RC_REW
286 #define VIEWER_SCREEN_RIGHT BUTTON_RC_FF
287 #define VIEWER_MENU BUTTON_RC_MENU
288 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
289 #define VIEWER_RC_QUIT BUTTON_REC
292 #elif CONFIG_KEYPAD == COWOND2_PAD
293 #define VIEWER_QUIT BUTTON_POWER
294 #define VIEWER_MENU BUTTON_MENU
296 #elif CONFIG_KEYPAD == IAUDIO67_PAD
297 #define VIEWER_QUIT BUTTON_POWER
298 #define VIEWER_PAGE_UP BUTTON_VOLUP
299 #define VIEWER_PAGE_DOWN BUTTON_VOLDOWN
300 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
301 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
302 #define VIEWER_MENU BUTTON_MENU
303 #define VIEWER_AUTOSCROLL BUTTON_PLAY
304 #define VIEWER_RC_QUIT BUTTON_STOP
306 /* Creative Zen Vision:M keys */
307 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
308 #define VIEWER_QUIT BUTTON_BACK
309 #define VIEWER_PAGE_UP BUTTON_UP
310 #define VIEWER_PAGE_DOWN BUTTON_DOWN
311 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
312 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
313 #define VIEWER_MENU BUTTON_MENU
314 #define VIEWER_AUTOSCROLL BUTTON_SELECT
316 /* Philips HDD1630 keys */
317 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
318 #define VIEWER_QUIT BUTTON_POWER
319 #define VIEWER_PAGE_UP BUTTON_UP
320 #define VIEWER_PAGE_DOWN BUTTON_DOWN
321 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
322 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
323 #define VIEWER_MENU BUTTON_MENU
324 #define VIEWER_AUTOSCROLL BUTTON_VIEW
326 /* Onda VX747 keys */
327 #elif CONFIG_KEYPAD == ONDAVX747_PAD
328 #define VIEWER_QUIT BUTTON_POWER
329 #define VIEWER_MENU BUTTON_MENU
331 /* SAMSUNG YH-820 / YH-920 / YH-925 keys */
332 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
333 #define VIEWER_QUIT BUTTON_REC
334 #define VIEWER_PAGE_UP BUTTON_UP
335 #define VIEWER_PAGE_DOWN BUTTON_DOWN
336 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
337 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
338 #define VIEWER_MENU BUTTON_PLAY
339 #define VIEWER_AUTOSCROLL BUTTON_REW
342 #error No keymap defined!
345 #ifdef HAVE_TOUCHSCREEN
347 #define VIEWER_QUIT BUTTON_TOPLEFT
349 #ifndef VIEWER_PAGE_UP
350 #define VIEWER_PAGE_UP BUTTON_TOPMIDDLE
352 #ifndef VIEWER_PAGE_DOWN
353 #define VIEWER_PAGE_DOWN BUTTON_BOTTOMMIDDLE
355 #ifndef VIEWER_SCREEN_LEFT
356 #define VIEWER_SCREEN_LEFT BUTTON_MIDLEFT
358 #ifndef VIEWER_SCREEN_RIGHT
359 #define VIEWER_SCREEN_RIGHT BUTTON_MIDRIGHT
362 #define VIEWER_MENU BUTTON_TOPRIGHT
364 #ifndef VIEWER_AUTOSCROLL
365 #define VIEWER_AUTOSCROLL BUTTON_CENTER
369 /* stuff for the bookmarking */
370 struct bookmarked_file_info
{
373 char filename
[MAX_PATH
];
376 struct bookmark_file_data
{
377 signed int bookmarked_files_count
;
378 struct bookmarked_file_info bookmarks
[];
391 REFLOW
, /* won't be set on charcell LCD, must be last */
399 enum codepages encoding
;
401 #ifdef HAVE_LCD_BITMAP
412 #endif /* HAVE_LCD_BITMAP */
419 int autoscroll_speed
;
423 struct preferences prefs
;
424 struct preferences old_prefs
;
426 static unsigned char *buffer
;
427 static long buffer_size
;
428 static unsigned char line_break
[] = {0,0x20,9,0xB,0xC,'-'};
429 static int display_columns
; /* number of (pixel) columns on the display */
430 static int display_lines
; /* number of lines on the display */
431 static int draw_columns
; /* number of (pixel) columns available for text */
432 static int par_indent_spaces
; /* number of spaces to indent first paragraph */
434 static const char *file_name
;
435 static long file_size
;
436 static long start_position
; /* position in the file after the viewer is started */
437 static bool mac_text
;
438 static long file_pos
; /* Position of the top of the buffer in the file */
439 static unsigned char *buffer_end
; /*Set to BUFFER_END() when file_pos changes*/
440 static int max_line_len
;
441 static unsigned char *screen_top_ptr
;
442 static unsigned char *next_screen_ptr
;
443 static unsigned char *next_screen_to_draw_ptr
;
444 static unsigned char *next_line_ptr
;
445 #ifdef HAVE_LCD_BITMAP
446 static struct font
*pf
;
450 int glyph_width(int ch
)
455 #ifdef HAVE_LCD_BITMAP
456 return rb
->font_get_width(pf
, ch
);
462 unsigned char* get_ucs(const unsigned char* str
, unsigned short* ch
)
464 unsigned char utf8_tmp
[6];
467 if (prefs
.encoding
== UTF_8
)
468 return (unsigned char*)rb
->utf8decode(str
, ch
);
470 count
= BUFFER_OOB(str
+2)? 1:2;
471 rb
->iso_decode(str
, utf8_tmp
, prefs
.encoding
, count
);
472 rb
->utf8decode(utf8_tmp
, ch
);
474 #ifdef HAVE_LCD_BITMAP
475 if (prefs
.encoding
>= SJIS
&& *str
>= 0x80
476 && !(prefs
.encoding
== SJIS
&& *str
> 0xA0 && *str
< 0xE0))
477 return (unsigned char*)str
+2;
480 return (unsigned char*)str
+1;
486 #define ADVANCE_COUNTERS(c) { width += glyph_width(c); k++; }
487 #define LINE_IS_FULL ((k>=MAX_COLUMNS-1) ||( width >= draw_columns))
488 #define LINE_IS_NOT_FULL ((k<MAX_COLUMNS-1) &&( width < draw_columns))
489 static unsigned char* crop_at_width(const unsigned char* p
)
493 const unsigned char *oldp
= p
;
497 while (LINE_IS_NOT_FULL
) {
500 ADVANCE_COUNTERS(ch
);
503 return (unsigned char*)oldp
;
506 static unsigned char* find_first_feed(const unsigned char* p
, int size
)
510 for (i
=0; i
< size
; i
++)
512 return (unsigned char*) p
+i
;
517 static unsigned char* find_last_feed(const unsigned char* p
, int size
)
521 for (i
=size
-1; i
>=0; i
--)
523 return (unsigned char*) p
+i
;
528 static unsigned char* find_last_space(const unsigned char* p
, int size
)
532 k
= (prefs
.line_mode
==JOIN
) || (prefs
.line_mode
==REFLOW
) ? 0:1;
534 if (!BUFFER_OOB(&p
[size
]))
535 for (j
=k
; j
< ((int) sizeof(line_break
)) - 1; j
++)
536 if (p
[size
] == line_break
[j
])
537 return (unsigned char*) p
+size
;
539 for (i
=size
-1; i
>=0; i
--)
540 for (j
=k
; j
< (int) sizeof(line_break
); j
++)
542 if (!((p
[i
] == '-') && (prefs
.word_mode
== WRAP
)))
543 if (p
[i
] == line_break
[j
])
544 return (unsigned char*) p
+i
;
550 static unsigned char* find_next_line(const unsigned char* cur_line
, bool *is_short
)
552 const unsigned char *next_line
= NULL
;
553 int size
, i
, j
, k
, width
, search_len
, spaces
, newlines
;
557 if (is_short
!= NULL
)
560 if BUFFER_OOB(cur_line
)
563 if (prefs
.view_mode
== WIDE
) {
564 search_len
= MAX_WIDTH
;
566 else { /* prefs.view_mode == NARROW */
567 search_len
= crop_at_width(cur_line
) - cur_line
;
570 size
= BUFFER_OOB(cur_line
+search_len
) ? buffer_end
-cur_line
: search_len
;
572 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
)) {
573 /* Need to scan ahead and possibly increase search_len and size,
574 or possibly set next_line at second hard return in a row. */
577 for (j
=k
=width
=spaces
=newlines
=0; ; j
++) {
578 if (BUFFER_OOB(cur_line
+j
))
581 size
= search_len
= j
;
588 if (prefs
.line_mode
== REFLOW
) {
591 next_line
= cur_line
+ size
;
592 return (unsigned char*) next_line
;
594 if (j
==0) /* i=1 is intentional */
595 for (i
=0; i
<par_indent_spaces
; i
++)
596 ADVANCE_COUNTERS(' ');
598 if (!first_chars
) spaces
++;
604 next_line
= cur_line
+ size
- spaces
;
605 if (next_line
!= cur_line
)
606 return (unsigned char*) next_line
;
612 if (BUFFER_OOB(cur_line
+size
) || size
> 2*search_len
)
615 spaces
= first_chars
? 0:1;
619 if (prefs
.line_mode
==JOIN
|| newlines
>0) {
622 ADVANCE_COUNTERS(' ');
624 size
= search_len
= j
;
630 /* REFLOW, multiple spaces between words: count only
631 * one. If more are needed, they will be added
635 ADVANCE_COUNTERS(' ');
637 size
= search_len
= j
;
648 /* find first hard return */
649 next_line
= find_first_feed(cur_line
, size
);
652 if (next_line
== NULL
)
653 if (size
== search_len
) {
654 if (prefs
.word_mode
== WRAP
) /* Find last space */
655 next_line
= find_last_space(cur_line
, size
);
657 if (next_line
== NULL
)
658 next_line
= crop_at_width(cur_line
);
660 if (prefs
.word_mode
== WRAP
)
662 i
<WRAP_TRIM
&& isspace(next_line
[0]) && !BUFFER_OOB(next_line
);
667 if (prefs
.line_mode
== EXPAND
)
668 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
669 if (next_line
[0] == 0)
670 if (next_line
!= cur_line
)
671 return (unsigned char*) next_line
;
673 /* If next_line is pointing to a zero, increment it; i.e.,
674 leave the terminator at the end of cur_line. If pointing
675 to a hyphen, increment only if there is room to display
676 the hyphen on current line (won't apply in WIDE mode,
677 since it's guarenteed there won't be room). */
678 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
679 if (next_line
[0] == 0)/* ||
680 (next_line[0] == '-' && next_line-cur_line < draw_columns)) */
683 if (BUFFER_OOB(next_line
))
689 return (unsigned char*) next_line
;
692 static unsigned char* find_prev_line(const unsigned char* cur_line
)
694 const unsigned char *prev_line
= NULL
;
695 const unsigned char *p
;
697 if BUFFER_OOB(cur_line
)
700 /* To wrap consistently at the same places, we must
701 start with a known hard return, then work downwards.
702 We can either search backwards for a hard return,
703 or simply start wrapping downwards from top of buffer.
704 If current line is not near top of buffer, this is
705 a file with long lines (paragraphs). We would need to
706 read earlier sectors before we could decide how to
707 properly wrap the lines above the current line, but
708 it probably is not worth the disk access. Instead,
709 start with top of buffer and wrap down from there.
710 This may result in some lines wrapping at different
711 points from where they wrap when scrolling down.
712 If buffer is at top of file, start at top of buffer. */
714 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
))
715 prev_line
= p
= NULL
;
717 prev_line
= p
= find_last_feed(buffer
, cur_line
-buffer
-1);
718 /* Null means no line feeds in buffer above current line. */
720 if (prev_line
== NULL
)
721 if (BUFFER_BOF() || cur_line
- buffer
> READ_PREV_ZONE
)
722 prev_line
= p
= buffer
;
723 /* (else return NULL and read previous block) */
725 /* Wrap downwards until too far, then use the one before. */
726 while (p
< cur_line
&& p
!= NULL
) {
728 p
= find_next_line(prev_line
, NULL
);
731 if (BUFFER_OOB(prev_line
))
734 return (unsigned char*) prev_line
;
737 static void fill_buffer(long pos
, unsigned char* buf
, unsigned size
)
739 /* Read from file and preprocess the data */
740 /* To minimize disk access, always read on sector boundaries */
742 bool found_CR
= false;
744 rb
->lseek(fd
, pos
, SEEK_SET
);
745 numread
= rb
->read(fd
, buf
, size
);
746 rb
->button_clear_queue(); /* clear button queue */
748 for(i
= 0; i
< numread
; i
++) {
765 case 0: /* No break between case 0 and default, intentionally */
778 static int read_and_synch(int direction
)
780 /* Read next (or prev) block, and reposition global pointers. */
781 /* direction: 1 for down (i.e., further into file), -1 for up */
782 int move_size
, move_vector
, offset
;
783 unsigned char *fill_buf
;
785 if (direction
== -1) /* up */ {
786 move_size
= SMALL_BLOCK_SIZE
;
788 fill_buf
= TOP_SECTOR
;
789 rb
->memcpy(BOTTOM_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
790 rb
->memcpy(MID_SECTOR
, TOP_SECTOR
, SMALL_BLOCK_SIZE
);
793 if (prefs
.view_mode
== WIDE
) {
794 /* WIDE mode needs more buffer so we have to read smaller blocks */
795 move_size
= SMALL_BLOCK_SIZE
;
796 offset
= LARGE_BLOCK_SIZE
;
797 fill_buf
= BOTTOM_SECTOR
;
798 rb
->memcpy(TOP_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
799 rb
->memcpy(MID_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
802 move_size
= LARGE_BLOCK_SIZE
;
803 offset
= SMALL_BLOCK_SIZE
;
804 fill_buf
= MID_SECTOR
;
805 rb
->memcpy(TOP_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
808 move_vector
= direction
* move_size
;
809 screen_top_ptr
-= move_vector
;
810 file_pos
+= move_vector
;
811 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
812 fill_buffer(file_pos
+ offset
, fill_buf
, move_size
);
816 static void viewer_scroll_up(void)
820 p
= find_prev_line(screen_top_ptr
);
821 if (p
== NULL
&& !BUFFER_BOF()) {
823 p
= find_prev_line(screen_top_ptr
);
829 static void viewer_scroll_down(void)
831 if (next_screen_ptr
!= NULL
)
832 screen_top_ptr
= next_line_ptr
;
835 #ifdef HAVE_LCD_BITMAP
836 static void viewer_scrollbar(void) {
837 int items
, min_shown
, max_shown
;
839 items
= (int) file_size
; /* (SH1 int is same as long) */
840 min_shown
= (int) file_pos
+ (screen_top_ptr
- buffer
);
842 if (next_screen_ptr
== NULL
)
845 max_shown
= min_shown
+ (next_screen_ptr
- screen_top_ptr
);
847 rb
->gui_scrollbar_draw(rb
->screens
[SCREEN_MAIN
],0, 0, SCROLLBAR_WIDTH
-1,
848 LCD_HEIGHT
, items
, min_shown
, max_shown
, VERTICAL
);
852 static void viewer_draw(int col
)
854 int i
, j
, k
, line_len
, line_width
, resynch_move
, spaces
, left_col
=0;
855 int width
, extra_spaces
, indent_spaces
, spaces_per_word
;
856 bool multiple_spacing
, line_is_short
;
858 unsigned char *str
, *oldstr
;
859 unsigned char *line_begin
;
860 unsigned char *line_end
;
862 unsigned char scratch_buffer
[MAX_COLUMNS
+ 1];
863 unsigned char utf8_buffer
[MAX_COLUMNS
*4 + 1];
864 unsigned char *endptr
;
866 /* If col==-1 do all calculations but don't display */
868 #ifdef HAVE_LCD_BITMAP
869 left_col
= prefs
.need_scrollbar
? SCROLLBAR_WIDTH
:0;
873 rb
->lcd_clear_display();
876 line_begin
= line_end
= screen_top_ptr
;
878 for (i
= 0; i
< display_lines
; i
++) {
879 if (BUFFER_OOB(line_end
))
880 break; /* Happens after display last line at BUFFER_EOF() */
882 line_begin
= line_end
;
883 line_end
= find_next_line(line_begin
, &line_is_short
);
885 if (line_end
== NULL
) {
887 if (i
< display_lines
- 1 && !BUFFER_BOF()) {
889 rb
->lcd_clear_display();
891 for (; i
< display_lines
- 1; i
++)
894 line_begin
= line_end
= screen_top_ptr
;
899 line_end
= buffer_end
;
903 resynch_move
= read_and_synch(1); /* Read block & move ptrs */
904 line_begin
-= resynch_move
;
906 next_line_ptr
-= resynch_move
;
908 line_end
= find_next_line(line_begin
, NULL
);
909 if (line_end
== NULL
) /* Should not really happen */
913 line_len
= line_end
- line_begin
;
915 /* calculate line_len */
916 str
= oldstr
= line_begin
;
918 while (str
< line_end
) {
920 str
= crop_at_width(str
);
923 line_width
= j
*draw_columns
;
924 while (oldstr
< line_end
) {
925 oldstr
= get_ucs(oldstr
, &ch
);
926 line_width
+= glyph_width(ch
);
929 if (prefs
.line_mode
== JOIN
) {
930 if (line_begin
[0] == 0) {
932 if (prefs
.word_mode
== CHOP
)
937 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
938 if (k
== MAX_COLUMNS
)
948 scratch_buffer
[k
++] = ' ';
953 scratch_buffer
[k
++] = ' ';
954 if (k
== MAX_COLUMNS
- 1)
957 scratch_buffer
[k
++] = c
;
962 scratch_buffer
[k
] = 0;
963 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
964 prefs
.encoding
, draw_columns
/glyph_width('i'));
968 else if (prefs
.line_mode
== REFLOW
) {
969 if (line_begin
[0] == 0) {
971 if (prefs
.word_mode
== CHOP
)
978 if (!line_is_short
) {
979 multiple_spacing
= false;
981 for (str
= line_begin
; str
< line_end
; ) {
982 str
= get_ucs(str
, &ch
);
986 if ((str
== line_begin
) && (prefs
.word_mode
==WRAP
))
987 /* special case: indent the paragraph,
988 * don't count spaces */
989 indent_spaces
= par_indent_spaces
;
990 else if (!multiple_spacing
)
992 multiple_spacing
= true;
995 multiple_spacing
= false;
996 width
+= glyph_width(ch
);
1000 if (multiple_spacing
) spaces
--;
1003 /* total number of spaces to insert between words */
1004 extra_spaces
= (draw_columns
-width
)/glyph_width(' ')
1006 /* number of spaces between each word*/
1007 spaces_per_word
= extra_spaces
/ spaces
;
1008 /* number of words with n+1 spaces (to fill up) */
1009 extra_spaces
= extra_spaces
% spaces
;
1010 if (spaces_per_word
> 2) { /* too much spacing is awful */
1011 spaces_per_word
= 3;
1014 } else { /* this doesn't matter much... no spaces anyway */
1015 spaces_per_word
= extra_spaces
= 0;
1017 } else { /* end of a paragraph: don't fill line */
1018 spaces_per_word
= 1;
1022 multiple_spacing
= false;
1023 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
1024 if (k
== MAX_COLUMNS
)
1031 if (j
==0 && prefs
.word_mode
==WRAP
) { /* indent paragraph */
1032 for (j
=0; j
<par_indent_spaces
; j
++)
1033 scratch_buffer
[k
++] = ' ';
1036 else if (!multiple_spacing
) {
1037 for (width
= spaces
<extra_spaces
? -1:0; width
< spaces_per_word
; width
++)
1038 scratch_buffer
[k
++] = ' ';
1041 multiple_spacing
= true;
1044 scratch_buffer
[k
++] = c
;
1045 multiple_spacing
= false;
1051 scratch_buffer
[k
] = 0;
1052 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
1053 prefs
.encoding
, k
-col
);
1057 else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */
1059 if (line_width
> col
) {
1060 str
= oldstr
= line_begin
;
1063 while( (width
<draw_columns
) && (oldstr
<line_end
) )
1065 oldstr
= get_ucs(oldstr
, &ch
);
1067 k
-= glyph_width(ch
);
1068 line_begin
= oldstr
;
1070 width
+= glyph_width(ch
);
1074 if(prefs
.view_mode
==WIDE
)
1075 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1076 prefs
.encoding
, oldstr
-line_begin
);
1078 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1079 prefs
.encoding
, line_end
-line_begin
);
1083 if (col
!= -1 && line_width
> col
)
1084 #ifdef HAVE_LCD_BITMAP
1085 rb
->lcd_putsxy(left_col
, i
*pf
->height
, utf8_buffer
);
1087 rb
->lcd_puts(left_col
, i
, utf8_buffer
);
1089 if (line_width
> max_line_len
)
1090 max_line_len
= line_width
;
1093 next_line_ptr
= line_end
;
1095 next_screen_ptr
= line_end
;
1096 if (BUFFER_OOB(next_screen_ptr
))
1097 next_screen_ptr
= NULL
;
1099 #ifdef HAVE_LCD_BITMAP
1100 next_screen_to_draw_ptr
= prefs
.page_mode
==OVERLAP
? line_begin
: next_screen_ptr
;
1102 if (prefs
.need_scrollbar
)
1105 next_screen_to_draw_ptr
= next_screen_ptr
;
1112 static void viewer_top(void)
1114 /* Read top of file into buffer
1115 and point screen pointer to top */
1119 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1120 fill_buffer(0, buffer
, buffer_size
);
1123 screen_top_ptr
= buffer
;
1126 static void viewer_bottom(void)
1128 /* Read bottom of file into buffer
1129 and point screen pointer to bottom */
1132 if (file_size
> buffer_size
) {
1133 /* Find last buffer in file, round up to next sector boundary */
1134 last_sectors
= file_size
- buffer_size
+ SMALL_BLOCK_SIZE
;
1135 last_sectors
/= SMALL_BLOCK_SIZE
;
1136 last_sectors
*= SMALL_BLOCK_SIZE
;
1142 if (file_pos
!= last_sectors
)
1144 file_pos
= last_sectors
;
1145 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1146 fill_buffer(last_sectors
, buffer
, buffer_size
);
1149 screen_top_ptr
= buffer_end
-1;
1152 #ifdef HAVE_LCD_BITMAP
1153 static void init_need_scrollbar(void) {
1154 /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
1155 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
1157 prefs
.need_scrollbar
= NEED_SCROLLBAR();
1158 draw_columns
= prefs
.need_scrollbar
? display_columns
-SCROLLBAR_WIDTH
: display_columns
;
1159 par_indent_spaces
= draw_columns
/(5*glyph_width(' '));
1162 #define init_need_scrollbar()
1165 static bool viewer_init(void)
1167 #ifdef HAVE_LCD_BITMAP
1169 pf
= rb
->font_get(FONT_UI
);
1171 display_lines
= LCD_HEIGHT
/ pf
->height
;
1172 draw_columns
= display_columns
= LCD_WIDTH
;
1174 /* REAL fixed pitch :) all chars use up 1 cell */
1176 draw_columns
= display_columns
= 11;
1177 par_indent_spaces
= 2;
1180 fd
= rb
->open(file_name
, O_RDONLY
);
1184 file_size
= rb
->filesize(fd
);
1188 /* Init mac_text value used in processing buffer */
1194 static void viewer_default_settings(void)
1196 prefs
.word_mode
= WRAP
;
1197 prefs
.line_mode
= NORMAL
;
1198 prefs
.view_mode
= NARROW
;
1199 prefs
.scroll_mode
= PAGE
;
1200 #ifdef HAVE_LCD_BITMAP
1201 prefs
.page_mode
= NO_OVERLAP
;
1202 prefs
.scrollbar_mode
= SB_OFF
;
1204 prefs
.autoscroll_speed
= 1;
1205 /* Set codepage to system default */
1206 prefs
.encoding
= rb
->global_settings
->default_codepage
;
1209 static void viewer_load_settings(void) /* same name as global, but not the same file.. */
1212 struct bookmark_file_data
*data
;
1213 struct bookmarked_file_info this_bookmark
;
1215 /* read settings file */
1216 settings_fd
=rb
->open(SETTINGS_FILE
, O_RDONLY
);
1217 if ((settings_fd
>= 0) && (rb
->filesize(settings_fd
) == sizeof(struct preferences
)))
1219 rb
->read(settings_fd
, &prefs
, sizeof(struct preferences
));
1220 rb
->close(settings_fd
);
1224 /* load default settings if there is no settings file */
1225 viewer_default_settings();
1228 rb
->memcpy(&old_prefs
, &prefs
, sizeof(struct preferences
));
1230 data
= (struct bookmark_file_data
*)buffer
; /* grab the text buffer */
1231 data
->bookmarked_files_count
= 0;
1233 /* read bookmarks if file exists */
1234 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_RDONLY
);
1235 if (settings_fd
>= 0)
1237 /* figure out how many items to read */
1238 rb
->read(settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1239 if (data
->bookmarked_files_count
> MAX_BOOKMARKED_FILES
)
1240 data
->bookmarked_files_count
= MAX_BOOKMARKED_FILES
;
1241 rb
->read(settings_fd
, data
->bookmarks
,
1242 sizeof(struct bookmarked_file_info
) * data
->bookmarked_files_count
);
1243 rb
->close(settings_fd
);
1247 screen_top_ptr
= buffer
;
1249 /* check if current file is in list */
1250 for (i
=0; i
< data
->bookmarked_files_count
; i
++)
1252 if (!rb
->strcmp(file_name
, data
->bookmarks
[i
].filename
))
1254 int screen_pos
= data
->bookmarks
[i
].file_position
+ data
->bookmarks
[i
].top_ptr_pos
;
1255 int screen_top
= screen_pos
% buffer_size
;
1256 file_pos
= screen_pos
- screen_top
;
1257 screen_top_ptr
= buffer
+ screen_top
;
1262 this_bookmark
.file_position
= file_pos
;
1263 this_bookmark
.top_ptr_pos
= screen_top_ptr
- buffer
;
1265 rb
->memset(&this_bookmark
.filename
[0],0,MAX_PATH
);
1266 rb
->strcpy(this_bookmark
.filename
,file_name
);
1268 /* prevent potential slot overflow */
1269 if (i
>= data
->bookmarked_files_count
)
1271 if (i
< MAX_BOOKMARKED_FILES
)
1272 data
->bookmarked_files_count
++;
1274 i
= MAX_BOOKMARKED_FILES
-1;
1277 /* write bookmark file with spare slot in first position
1278 to be filled in by viewer_save_settings */
1279 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1280 if (settings_fd
>=0 )
1283 rb
->write (settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1285 /* write the current bookmark */
1286 rb
->write (settings_fd
, &this_bookmark
, sizeof(struct bookmarked_file_info
));
1288 /* write everything that was before this bookmark */
1289 rb
->write (settings_fd
, data
->bookmarks
, sizeof(struct bookmarked_file_info
)*i
);
1291 rb
->close(settings_fd
);
1294 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1296 if (BUFFER_OOB(screen_top_ptr
))
1298 screen_top_ptr
= buffer
;
1301 fill_buffer(file_pos
, buffer
, buffer_size
);
1303 /* remember the current position */
1304 start_position
= file_pos
+ screen_top_ptr
- buffer
;
1306 init_need_scrollbar();
1309 static void viewer_save_settings(void)/* same name as global, but not the same file.. */
1313 /* save the viewer settings if they have been changed */
1314 if (rb
->memcmp(&prefs
, &old_prefs
, sizeof(struct preferences
)))
1316 settings_fd
= rb
->creat(SETTINGS_FILE
); /* create the settings file */
1318 if (settings_fd
>= 0 )
1320 rb
->write (settings_fd
, &prefs
, sizeof(struct preferences
));
1321 rb
->close(settings_fd
);
1325 /* save the bookmark if the position has changed */
1326 if (file_pos
+ screen_top_ptr
- buffer
!= start_position
)
1328 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1330 if (settings_fd
>= 0 )
1332 struct bookmarked_file_info b
;
1333 b
.file_position
= file_pos
+ screen_top_ptr
- buffer
;
1334 b
.top_ptr_pos
= 0; /* this is only kept for legassy reasons */
1335 rb
->memset(&b
.filename
[0],0,MAX_PATH
);
1336 rb
->strcpy(b
.filename
,file_name
);
1337 rb
->lseek(settings_fd
,sizeof(signed int),SEEK_SET
);
1338 rb
->write (settings_fd
, &b
, sizeof(struct bookmarked_file_info
));
1339 rb
->close(settings_fd
);
1344 static void viewer_exit(void *parameter
)
1348 viewer_save_settings();
1352 static int col_limit(int col
)
1357 if (col
> max_line_len
- 2*glyph_width('o'))
1358 col
= max_line_len
- 2*glyph_width('o');
1363 /* settings helper functions */
1365 static bool encoding_setting(void)
1367 static struct opt_items names
[NUM_CODEPAGES
];
1370 for (idx
= 0; idx
< NUM_CODEPAGES
; idx
++)
1372 names
[idx
].string
= rb
->get_codepage_name(idx
);
1373 names
[idx
].voice_id
= -1;
1376 return rb
->set_option("Encoding", &prefs
.encoding
, INT
, names
,
1377 sizeof(names
) / sizeof(names
[0]), NULL
);
1380 static bool word_wrap_setting(void)
1382 static const struct opt_items names
[] = {
1384 {"Off (Chop Words)", -1},
1387 return rb
->set_option("Word Wrap", &prefs
.word_mode
, INT
,
1391 static bool line_mode_setting(void)
1393 static const struct opt_items names
[] = {
1396 {"Expand Lines", -1},
1397 #ifdef HAVE_LCD_BITMAP
1398 {"Reflow Lines", -1},
1402 return rb
->set_option("Line Mode", &prefs
.line_mode
, INT
, names
,
1403 sizeof(names
) / sizeof(names
[0]), NULL
);
1406 static bool view_mode_setting(void)
1408 static const struct opt_items names
[] = {
1409 {"No (Narrow)", -1},
1413 ret
= rb
->set_option("Wide View", &prefs
.view_mode
, INT
,
1415 if (prefs
.view_mode
== NARROW
)
1420 static bool scroll_mode_setting(void)
1422 static const struct opt_items names
[] = {
1423 {"Scroll by Page", -1},
1424 {"Scroll by Line", -1},
1427 return rb
->set_option("Scroll Mode", &prefs
.scroll_mode
, INT
,
1431 #ifdef HAVE_LCD_BITMAP
1432 static bool page_mode_setting(void)
1434 static const struct opt_items names
[] = {
1439 return rb
->set_option("Overlap Pages", &prefs
.page_mode
, INT
,
1443 static bool scrollbar_setting(void)
1445 static const struct opt_items names
[] = {
1450 return rb
->set_option("Show Scrollbar", &prefs
.scrollbar_mode
, INT
,
1455 static bool autoscroll_speed_setting(void)
1457 return rb
->set_int("Auto-scroll Speed", "", UNIT_INT
,
1458 &prefs
.autoscroll_speed
, NULL
, 1, 1, 10, NULL
);
1461 MENUITEM_FUNCTION(encoding_item
, 0, "Encoding", encoding_setting
,
1462 NULL
, NULL
, Icon_NOICON
);
1463 MENUITEM_FUNCTION(word_wrap_item
, 0, "Word Wrap", word_wrap_setting
,
1464 NULL
, NULL
, Icon_NOICON
);
1465 MENUITEM_FUNCTION(line_mode_item
, 0, "Line Mode", line_mode_setting
,
1466 NULL
, NULL
, Icon_NOICON
);
1467 MENUITEM_FUNCTION(view_mode_item
, 0, "Wide View", view_mode_setting
,
1468 NULL
, NULL
, Icon_NOICON
);
1469 #ifdef HAVE_LCD_BITMAP
1470 MENUITEM_FUNCTION(scrollbar_item
, 0, "Show Scrollbar", scrollbar_setting
,
1471 NULL
, NULL
, Icon_NOICON
);
1472 MENUITEM_FUNCTION(page_mode_item
, 0, "Overlap Pages", page_mode_setting
,
1473 NULL
, NULL
, Icon_NOICON
);
1475 MENUITEM_FUNCTION(scroll_mode_item
, 0, "Scroll Mode", scroll_mode_setting
,
1476 NULL
, NULL
, Icon_NOICON
);
1477 MENUITEM_FUNCTION(autoscroll_speed_item
, 0, "Auto-Scroll Speed",
1478 autoscroll_speed_setting
, NULL
, NULL
, Icon_NOICON
);
1479 MAKE_MENU(option_menu
, "Viewer Options", NULL
, Icon_NOICON
,
1480 &encoding_item
, &word_wrap_item
, &line_mode_item
, &view_mode_item
,
1481 #ifdef HAVE_LCD_BITMAP
1482 &scrollbar_item
, &page_mode_item
,
1484 &scroll_mode_item
, &autoscroll_speed_item
);
1486 static bool viewer_options_menu(void)
1489 result
= (rb
->do_menu(&option_menu
, NULL
, NULL
, false) == MENU_ATTACHED_USB
);
1491 #ifdef HAVE_LCD_BITMAP
1492 /* Show-scrollbar mode for current view-width mode */
1493 init_need_scrollbar();
1498 static void viewer_menu(void)
1501 MENUITEM_STRINGLIST(menu
, "Viewer Menu", NULL
,
1502 "Return", "Viewer Options",
1503 "Show Playback Menu", "Quit");
1505 result
= rb
->do_menu(&menu
, NULL
, NULL
, false);
1508 case 0: /* return */
1510 case 1: /* change settings */
1511 done
= viewer_options_menu();
1513 case 2: /* playback control */
1514 playback_control(NULL
);
1524 enum plugin_status
plugin_start(const void* file
)
1527 int lastbutton
= BUTTON_NONE
;
1528 bool autoscroll
= false;
1531 old_tick
= *rb
->current_tick
;
1533 /* get the plugin buffer */
1534 buffer
= rb
->plugin_get_buffer((size_t *)&buffer_size
);
1537 return PLUGIN_ERROR
;
1542 rb
->splash(HZ
, "Error opening file.");
1543 return PLUGIN_ERROR
;
1546 viewer_load_settings(); /* load the preferences and bookmark */
1549 rb
->lcd_set_backdrop(NULL
);
1558 if(old_tick
<= *rb
->current_tick
- (110-prefs
.autoscroll_speed
*10))
1560 viewer_scroll_down();
1562 old_tick
= *rb
->current_tick
;
1566 button
= rb
->button_get_w_tmo(HZ
/10);
1572 case VIEWER_AUTOSCROLL
:
1573 #ifdef VIEWER_AUTOSCROLL_PRE
1574 if (lastbutton
!= VIEWER_AUTOSCROLL_PRE
)
1577 autoscroll
= !autoscroll
;
1580 case VIEWER_PAGE_UP
:
1581 case VIEWER_PAGE_UP
| BUTTON_REPEAT
:
1582 if (prefs
.scroll_mode
== PAGE
)
1585 #ifdef HAVE_LCD_BITMAP
1586 for (i
= prefs
.page_mode
==OVERLAP
? 1:0; i
< display_lines
; i
++)
1588 for (i
= 0; i
< display_lines
; i
++)
1594 old_tick
= *rb
->current_tick
;
1598 case VIEWER_PAGE_DOWN
:
1599 case VIEWER_PAGE_DOWN
| BUTTON_REPEAT
:
1600 if (prefs
.scroll_mode
== PAGE
)
1603 if (next_screen_ptr
!= NULL
)
1604 screen_top_ptr
= next_screen_to_draw_ptr
;
1607 viewer_scroll_down();
1608 old_tick
= *rb
->current_tick
;
1612 case VIEWER_SCREEN_LEFT
:
1613 case VIEWER_SCREEN_LEFT
| BUTTON_REPEAT
:
1614 if (prefs
.view_mode
== WIDE
) {
1616 col
-= draw_columns
;
1617 col
= col_limit(col
);
1619 else { /* prefs.view_mode == NARROW */
1627 case VIEWER_SCREEN_RIGHT
:
1628 case VIEWER_SCREEN_RIGHT
| BUTTON_REPEAT
:
1629 if (prefs
.view_mode
== WIDE
) {
1631 col
+= draw_columns
;
1632 col
= col_limit(col
);
1634 else { /* prefs.view_mode == NARROW */
1635 /* Bottom of file */
1642 #ifdef VIEWER_LINE_UP
1643 case VIEWER_LINE_UP
:
1644 case VIEWER_LINE_UP
| BUTTON_REPEAT
:
1645 /* Scroll up one line */
1647 old_tick
= *rb
->current_tick
;
1651 case VIEWER_LINE_DOWN
:
1652 case VIEWER_LINE_DOWN
| BUTTON_REPEAT
:
1653 /* Scroll down one line */
1654 if (next_screen_ptr
!= NULL
)
1655 screen_top_ptr
= next_line_ptr
;
1656 old_tick
= *rb
->current_tick
;
1660 #ifdef VIEWER_COLUMN_LEFT
1661 case VIEWER_COLUMN_LEFT
:
1662 case VIEWER_COLUMN_LEFT
| BUTTON_REPEAT
:
1663 if (prefs
.view_mode
== WIDE
) {
1664 /* Scroll left one column */
1665 col
-= glyph_width('o');
1666 col
= col_limit(col
);
1671 case VIEWER_COLUMN_RIGHT
:
1672 case VIEWER_COLUMN_RIGHT
| BUTTON_REPEAT
:
1673 if (prefs
.view_mode
== WIDE
) {
1674 /* Scroll right one column */
1675 col
+= glyph_width('o');
1676 col
= col_limit(col
);
1682 #ifdef VIEWER_RC_QUIT
1683 case VIEWER_RC_QUIT
:
1691 if (rb
->default_event_handler_ex(button
, viewer_exit
, NULL
)
1692 == SYS_USB_CONNECTED
)
1693 return PLUGIN_USB_CONNECTED
;
1696 if (button
!= BUTTON_NONE
)
1698 lastbutton
= button
;