1 /***************************************************************************
4 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
11 * Copyright (C) 2002 Gilles Roux, 2003 Garrett Derner
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
24 #include "lib/playback_control.h"
28 #define SETTINGS_FILE VIEWERS_DIR "/viewer.dat" /* binary file, so dont use .cfg */
29 #define BOOKMARKS_FILE VIEWERS_DIR "/viewer_bookmarks.dat"
31 #define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */
32 #define MAX_COLUMNS 64 /* Max displayable string len (over-estimate) */
33 #define MAX_WIDTH 910 /* Max line length in WIDE mode */
34 #define READ_PREV_ZONE 910 /* Arbitrary number less than SMALL_BLOCK_SIZE */
35 #define SMALL_BLOCK_SIZE 0x1000 /* 4k: Smallest file chunk we will read */
36 #define LARGE_BLOCK_SIZE 0x2000 /* 8k: Preferable size of file chunk to read */
37 #define TOP_SECTOR buffer
38 #define MID_SECTOR (buffer + SMALL_BLOCK_SIZE)
39 #define BOTTOM_SECTOR (buffer + 2*(SMALL_BLOCK_SIZE))
40 #undef SCROLLBAR_WIDTH
41 #define SCROLLBAR_WIDTH rb->global_settings->scrollbar_width
43 #define MAX_BOOKMARKED_FILES ((buffer_size/(signed)sizeof(struct bookmarked_file_info))-1)
45 /* Out-Of-Bounds test for any pointer to data in the buffer */
46 #define BUFFER_OOB(p) ((p) < buffer || (p) >= buffer_end)
48 /* Does the buffer contain the beginning of the file? */
49 #define BUFFER_BOF() (file_pos==0)
51 /* Does the buffer contain the end of the file? */
52 #define BUFFER_EOF() (file_size-file_pos <= buffer_size)
54 /* Formula for the endpoint address outside of buffer data */
55 #define BUFFER_END() \
56 ((BUFFER_EOF()) ? (file_size-file_pos+buffer) : (buffer+buffer_size))
58 /* Is the entire file being shown in one screen? */
59 #define ONE_SCREEN_FITS_ALL() \
60 (next_screen_ptr==NULL && screen_top_ptr==buffer && BUFFER_BOF())
62 /* Is a scrollbar called for on the current screen? */
63 #define NEED_SCROLLBAR() \
64 ((!(ONE_SCREEN_FITS_ALL())) && (prefs.scrollbar_mode==SB_ON))
66 /* variable button definitions */
69 #if CONFIG_KEYPAD == RECORDER_PAD
70 #define VIEWER_QUIT BUTTON_OFF
71 #define VIEWER_PAGE_UP BUTTON_UP
72 #define VIEWER_PAGE_DOWN BUTTON_DOWN
73 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
74 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
75 #define VIEWER_MENU BUTTON_F1
76 #define VIEWER_AUTOSCROLL BUTTON_PLAY
77 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
78 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
79 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
80 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
82 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
83 #define VIEWER_QUIT BUTTON_OFF
84 #define VIEWER_PAGE_UP BUTTON_UP
85 #define VIEWER_PAGE_DOWN BUTTON_DOWN
86 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
87 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
88 #define VIEWER_MENU BUTTON_F1
89 #define VIEWER_AUTOSCROLL BUTTON_SELECT
90 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
91 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
92 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
93 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
96 #elif CONFIG_KEYPAD == ONDIO_PAD
97 #define VIEWER_QUIT BUTTON_OFF
98 #define VIEWER_PAGE_UP BUTTON_UP
99 #define VIEWER_PAGE_DOWN BUTTON_DOWN
100 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
101 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
102 #define VIEWER_MENU (BUTTON_MENU|BUTTON_REPEAT)
103 #define VIEWER_AUTOSCROLL_PRE BUTTON_MENU
104 #define VIEWER_AUTOSCROLL (BUTTON_MENU|BUTTON_REL)
107 #elif CONFIG_KEYPAD == PLAYER_PAD
108 #define VIEWER_QUIT BUTTON_STOP
109 #define VIEWER_PAGE_UP BUTTON_LEFT
110 #define VIEWER_PAGE_DOWN BUTTON_RIGHT
111 #define VIEWER_SCREEN_LEFT (BUTTON_ON|BUTTON_LEFT)
112 #define VIEWER_SCREEN_RIGHT (BUTTON_ON|BUTTON_RIGHT)
113 #define VIEWER_MENU BUTTON_MENU
114 #define VIEWER_AUTOSCROLL BUTTON_PLAY
116 /* iRiver H1x0 && H3x0 keys */
117 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
118 (CONFIG_KEYPAD == IRIVER_H300_PAD)
119 #define VIEWER_QUIT BUTTON_OFF
120 #define VIEWER_PAGE_UP BUTTON_UP
121 #define VIEWER_PAGE_DOWN BUTTON_DOWN
122 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
123 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
124 #define VIEWER_MENU BUTTON_MODE
125 #define VIEWER_AUTOSCROLL BUTTON_SELECT
126 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
127 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
128 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
129 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
131 #define VIEWER_RC_QUIT BUTTON_RC_STOP
134 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
135 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
136 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
137 #define VIEWER_QUIT_PRE BUTTON_SELECT
138 #define VIEWER_QUIT (BUTTON_SELECT | BUTTON_MENU)
139 #define VIEWER_PAGE_UP BUTTON_SCROLL_BACK
140 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_FWD
141 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
142 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
143 #define VIEWER_MENU BUTTON_MENU
144 #define VIEWER_AUTOSCROLL BUTTON_PLAY
147 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
148 #define VIEWER_QUIT BUTTON_PLAY
149 #define VIEWER_PAGE_UP BUTTON_UP
150 #define VIEWER_PAGE_DOWN BUTTON_DOWN
151 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
152 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
153 #define VIEWER_MENU BUTTON_MODE
154 #define VIEWER_AUTOSCROLL BUTTON_SELECT
157 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
158 #define VIEWER_QUIT BUTTON_POWER
159 #define VIEWER_PAGE_UP BUTTON_UP
160 #define VIEWER_PAGE_DOWN BUTTON_DOWN
161 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
162 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
163 #define VIEWER_MENU BUTTON_SELECT
164 #define VIEWER_AUTOSCROLL BUTTON_PLAY
167 #elif CONFIG_KEYPAD == GIGABEAT_PAD
168 #define VIEWER_QUIT BUTTON_POWER
169 #define VIEWER_PAGE_UP BUTTON_UP
170 #define VIEWER_PAGE_DOWN BUTTON_DOWN
171 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
172 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
173 #define VIEWER_MENU BUTTON_MENU
174 #define VIEWER_AUTOSCROLL BUTTON_A
176 /* Sansa E200 keys */
177 #elif CONFIG_KEYPAD == SANSA_E200_PAD
178 #define VIEWER_QUIT BUTTON_POWER
179 #define VIEWER_PAGE_UP BUTTON_UP
180 #define VIEWER_PAGE_DOWN BUTTON_DOWN
181 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
182 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
183 #define VIEWER_MENU BUTTON_SELECT
184 #define VIEWER_AUTOSCROLL BUTTON_REC
185 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
186 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
188 /* Sansa Fuze keys */
189 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
190 #define VIEWER_QUIT (BUTTON_HOME|BUTTON_REPEAT)
191 #define VIEWER_PAGE_UP BUTTON_UP
192 #define VIEWER_PAGE_DOWN BUTTON_DOWN
193 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
194 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
195 #define VIEWER_MENU BUTTON_SELECT|BUTTON_REPEAT
196 #define VIEWER_AUTOSCROLL BUTTON_SELECT|BUTTON_DOWN
197 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
198 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
200 /* Sansa C200 keys */
201 #elif CONFIG_KEYPAD == SANSA_C200_PAD
202 #define VIEWER_QUIT BUTTON_POWER
203 #define VIEWER_PAGE_UP BUTTON_VOL_UP
204 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
205 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
206 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
207 #define VIEWER_MENU BUTTON_SELECT
208 #define VIEWER_AUTOSCROLL BUTTON_REC
209 #define VIEWER_LINE_UP BUTTON_UP
210 #define VIEWER_LINE_DOWN BUTTON_DOWN
212 /* Sansa Clip keys */
213 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
214 #define VIEWER_QUIT BUTTON_POWER
215 #define VIEWER_PAGE_UP BUTTON_VOL_UP
216 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
217 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
218 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
219 #define VIEWER_MENU BUTTON_SELECT
220 #define VIEWER_AUTOSCROLL BUTTON_HOME
221 #define VIEWER_LINE_UP BUTTON_UP
222 #define VIEWER_LINE_DOWN BUTTON_DOWN
224 /* Sansa M200 keys */
225 #elif CONFIG_KEYPAD == SANSA_M200_PAD
226 #define VIEWER_QUIT BUTTON_POWER
227 #define VIEWER_PAGE_UP BUTTON_VOL_UP
228 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
229 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
230 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
231 #define VIEWER_MENU (BUTTON_SELECT | BUTTON_UP)
232 #define VIEWER_AUTOSCROLL (BUTTON_SELECT | BUTTON_REL)
233 #define VIEWER_LINE_UP BUTTON_UP
234 #define VIEWER_LINE_DOWN BUTTON_DOWN
236 /* iriver H10 keys */
237 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
238 #define VIEWER_QUIT BUTTON_POWER
239 #define VIEWER_PAGE_UP BUTTON_SCROLL_UP
240 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_DOWN
241 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
242 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
243 #define VIEWER_MENU BUTTON_REW
244 #define VIEWER_AUTOSCROLL BUTTON_PLAY
247 #elif CONFIG_KEYPAD == MROBE500_PAD
248 #define VIEWER_QUIT BUTTON_POWER
249 #define VIEWER_PAGE_UP BUTTON_RC_PLAY
250 #define VIEWER_PAGE_DOWN BUTTON_RC_DOWN
251 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
252 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
253 #define VIEWER_MENU BUTTON_RC_HEART
254 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
257 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
258 #define VIEWER_QUIT BUTTON_BACK
259 #define VIEWER_PAGE_UP BUTTON_PREV
260 #define VIEWER_PAGE_DOWN BUTTON_NEXT
261 #define VIEWER_SCREEN_LEFT (BUTTON_PLAY | BUTTON_LEFT)
262 #define VIEWER_SCREEN_RIGHT (BUTTON_PLAY | BUTTON_RIGHT)
263 #define VIEWER_MENU BUTTON_MENU
264 #define VIEWER_AUTOSCROLL_PRE BUTTON_PLAY
265 #define VIEWER_AUTOSCROLL (BUTTON_PLAY|BUTTON_REL)
266 #define VIEWER_LINE_UP BUTTON_UP
267 #define VIEWER_LINE_DOWN BUTTON_DOWN
268 #define VIEWER_COLUMN_LEFT BUTTON_LEFT
269 #define VIEWER_COLUMN_RIGHT BUTTON_RIGHT
272 #elif CONFIG_KEYPAD == MROBE100_PAD
273 #define VIEWER_QUIT BUTTON_POWER
274 #define VIEWER_PAGE_UP BUTTON_UP
275 #define VIEWER_PAGE_DOWN BUTTON_DOWN
276 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
277 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
278 #define VIEWER_MENU BUTTON_MENU
279 #define VIEWER_AUTOSCROLL BUTTON_DISPLAY
282 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
283 #define VIEWER_QUIT BUTTON_RC_REC
284 #define VIEWER_PAGE_UP BUTTON_RC_VOL_UP
285 #define VIEWER_PAGE_DOWN BUTTON_RC_VOL_DOWN
286 #define VIEWER_SCREEN_LEFT BUTTON_RC_REW
287 #define VIEWER_SCREEN_RIGHT BUTTON_RC_FF
288 #define VIEWER_MENU BUTTON_RC_MENU
289 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
290 #define VIEWER_RC_QUIT BUTTON_REC
293 #elif CONFIG_KEYPAD == COWOND2_PAD
294 #define VIEWER_QUIT BUTTON_POWER
295 #define VIEWER_MENU BUTTON_MENU
297 #elif CONFIG_KEYPAD == IAUDIO67_PAD
298 #define VIEWER_QUIT BUTTON_POWER
299 #define VIEWER_PAGE_UP BUTTON_VOLUP
300 #define VIEWER_PAGE_DOWN BUTTON_VOLDOWN
301 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
302 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
303 #define VIEWER_MENU BUTTON_MENU
304 #define VIEWER_AUTOSCROLL BUTTON_PLAY
305 #define VIEWER_RC_QUIT BUTTON_STOP
307 /* Creative Zen Vision:M keys */
308 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
309 #define VIEWER_QUIT BUTTON_BACK
310 #define VIEWER_PAGE_UP BUTTON_UP
311 #define VIEWER_PAGE_DOWN BUTTON_DOWN
312 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
313 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
314 #define VIEWER_MENU BUTTON_MENU
315 #define VIEWER_AUTOSCROLL BUTTON_SELECT
317 /* Philips HDD1630 keys */
318 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
319 #define VIEWER_QUIT BUTTON_POWER
320 #define VIEWER_PAGE_UP BUTTON_UP
321 #define VIEWER_PAGE_DOWN BUTTON_DOWN
322 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
323 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
324 #define VIEWER_MENU BUTTON_MENU
325 #define VIEWER_AUTOSCROLL BUTTON_VIEW
327 /* Philips SA9200 keys */
328 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
329 #define VIEWER_QUIT BUTTON_POWER
330 #define VIEWER_PAGE_UP BUTTON_UP
331 #define VIEWER_PAGE_DOWN BUTTON_DOWN
332 #define VIEWER_SCREEN_LEFT BUTTON_PREV
333 #define VIEWER_SCREEN_RIGHT BUTTON_NEXT
334 #define VIEWER_MENU BUTTON_MENU
335 #define VIEWER_AUTOSCROLL BUTTON_PLAY
337 /* Onda VX747 keys */
338 #elif CONFIG_KEYPAD == ONDAVX747_PAD
339 #define VIEWER_QUIT BUTTON_POWER
340 #define VIEWER_MENU BUTTON_MENU
342 /* Onda VX777 keys */
343 #elif CONFIG_KEYPAD == ONDAVX777_PAD
344 #define VIEWER_QUIT BUTTON_POWER
346 /* SAMSUNG YH-820 / YH-920 / YH-925 keys */
347 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
348 #define VIEWER_QUIT BUTTON_REC
349 #define VIEWER_PAGE_UP BUTTON_UP
350 #define VIEWER_PAGE_DOWN BUTTON_DOWN
351 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
352 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
353 #define VIEWER_MENU BUTTON_PLAY
354 #define VIEWER_AUTOSCROLL BUTTON_REW
357 #error No keymap defined!
360 #ifdef HAVE_TOUCHSCREEN
362 #define VIEWER_QUIT BUTTON_TOPLEFT
364 #ifndef VIEWER_PAGE_UP
365 #define VIEWER_PAGE_UP BUTTON_TOPMIDDLE
367 #ifndef VIEWER_PAGE_DOWN
368 #define VIEWER_PAGE_DOWN BUTTON_BOTTOMMIDDLE
370 #ifndef VIEWER_SCREEN_LEFT
371 #define VIEWER_SCREEN_LEFT BUTTON_MIDLEFT
373 #ifndef VIEWER_SCREEN_RIGHT
374 #define VIEWER_SCREEN_RIGHT BUTTON_MIDRIGHT
377 #define VIEWER_MENU BUTTON_TOPRIGHT
379 #ifndef VIEWER_AUTOSCROLL
380 #define VIEWER_AUTOSCROLL BUTTON_CENTER
384 /* stuff for the bookmarking */
385 struct bookmarked_file_info
{
388 char filename
[MAX_PATH
];
391 struct bookmark_file_data
{
392 signed int bookmarked_files_count
;
393 struct bookmarked_file_info bookmarks
[];
406 REFLOW
, /* won't be set on charcell LCD, must be last */
414 enum codepages encoding
;
416 #ifdef HAVE_LCD_BITMAP
427 #endif /* HAVE_LCD_BITMAP */
434 int autoscroll_speed
;
438 struct preferences prefs
;
439 struct preferences old_prefs
;
441 static unsigned char *buffer
;
442 static long buffer_size
;
443 static unsigned char line_break
[] = {0,0x20,9,0xB,0xC,'-'};
444 static int display_columns
; /* number of (pixel) columns on the display */
445 static int display_lines
; /* number of lines on the display */
446 static int draw_columns
; /* number of (pixel) columns available for text */
447 static int par_indent_spaces
; /* number of spaces to indent first paragraph */
449 static const char *file_name
;
450 static long file_size
;
451 static long start_position
; /* position in the file after the viewer is started */
452 static bool mac_text
;
453 static long file_pos
; /* Position of the top of the buffer in the file */
454 static unsigned char *buffer_end
; /*Set to BUFFER_END() when file_pos changes*/
455 static int max_line_len
;
456 static unsigned char *screen_top_ptr
;
457 static unsigned char *next_screen_ptr
;
458 static unsigned char *next_screen_to_draw_ptr
;
459 static unsigned char *next_line_ptr
;
460 #ifdef HAVE_LCD_BITMAP
461 static struct font
*pf
;
465 int glyph_width(int ch
)
470 #ifdef HAVE_LCD_BITMAP
471 return rb
->font_get_width(pf
, ch
);
477 unsigned char* get_ucs(const unsigned char* str
, unsigned short* ch
)
479 unsigned char utf8_tmp
[6];
482 if (prefs
.encoding
== UTF_8
)
483 return (unsigned char*)rb
->utf8decode(str
, ch
);
485 count
= BUFFER_OOB(str
+2)? 1:2;
486 rb
->iso_decode(str
, utf8_tmp
, prefs
.encoding
, count
);
487 rb
->utf8decode(utf8_tmp
, ch
);
489 #ifdef HAVE_LCD_BITMAP
490 if (prefs
.encoding
>= SJIS
&& *str
>= 0x80
491 && !(prefs
.encoding
== SJIS
&& *str
> 0xA0 && *str
< 0xE0))
492 return (unsigned char*)str
+2;
495 return (unsigned char*)str
+1;
501 #define ADVANCE_COUNTERS(c) { width += glyph_width(c); k++; }
502 #define LINE_IS_FULL ((k>=MAX_COLUMNS-1) ||( width >= draw_columns))
503 #define LINE_IS_NOT_FULL ((k<MAX_COLUMNS-1) &&( width < draw_columns))
504 static unsigned char* crop_at_width(const unsigned char* p
)
508 const unsigned char *oldp
= p
;
512 while (LINE_IS_NOT_FULL
) {
515 ADVANCE_COUNTERS(ch
);
518 return (unsigned char*)oldp
;
521 static unsigned char* find_first_feed(const unsigned char* p
, int size
)
525 for (i
=0; i
< size
; i
++)
527 return (unsigned char*) p
+i
;
532 static unsigned char* find_last_feed(const unsigned char* p
, int size
)
536 for (i
=size
-1; i
>=0; i
--)
538 return (unsigned char*) p
+i
;
543 static unsigned char* find_last_space(const unsigned char* p
, int size
)
547 k
= (prefs
.line_mode
==JOIN
) || (prefs
.line_mode
==REFLOW
) ? 0:1;
549 if (!BUFFER_OOB(&p
[size
]))
550 for (j
=k
; j
< ((int) sizeof(line_break
)) - 1; j
++)
551 if (p
[size
] == line_break
[j
])
552 return (unsigned char*) p
+size
;
554 for (i
=size
-1; i
>=0; i
--)
555 for (j
=k
; j
< (int) sizeof(line_break
); j
++)
557 if (!((p
[i
] == '-') && (prefs
.word_mode
== WRAP
)))
558 if (p
[i
] == line_break
[j
])
559 return (unsigned char*) p
+i
;
565 static unsigned char* find_next_line(const unsigned char* cur_line
, bool *is_short
)
567 const unsigned char *next_line
= NULL
;
568 int size
, i
, j
, k
, width
, search_len
, spaces
, newlines
;
572 if (is_short
!= NULL
)
575 if BUFFER_OOB(cur_line
)
578 if (prefs
.view_mode
== WIDE
) {
579 search_len
= MAX_WIDTH
;
581 else { /* prefs.view_mode == NARROW */
582 search_len
= crop_at_width(cur_line
) - cur_line
;
585 size
= BUFFER_OOB(cur_line
+search_len
) ? buffer_end
-cur_line
: search_len
;
587 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
)) {
588 /* Need to scan ahead and possibly increase search_len and size,
589 or possibly set next_line at second hard return in a row. */
592 for (j
=k
=width
=spaces
=newlines
=0; ; j
++) {
593 if (BUFFER_OOB(cur_line
+j
))
596 size
= search_len
= j
;
603 if (prefs
.line_mode
== REFLOW
) {
606 next_line
= cur_line
+ size
;
607 return (unsigned char*) next_line
;
609 if (j
==0) /* i=1 is intentional */
610 for (i
=0; i
<par_indent_spaces
; i
++)
611 ADVANCE_COUNTERS(' ');
613 if (!first_chars
) spaces
++;
619 next_line
= cur_line
+ size
- spaces
;
620 if (next_line
!= cur_line
)
621 return (unsigned char*) next_line
;
627 if (BUFFER_OOB(cur_line
+size
) || size
> 2*search_len
)
630 spaces
= first_chars
? 0:1;
634 if (prefs
.line_mode
==JOIN
|| newlines
>0) {
637 ADVANCE_COUNTERS(' ');
639 size
= search_len
= j
;
645 /* REFLOW, multiple spaces between words: count only
646 * one. If more are needed, they will be added
650 ADVANCE_COUNTERS(' ');
652 size
= search_len
= j
;
663 /* find first hard return */
664 next_line
= find_first_feed(cur_line
, size
);
667 if (next_line
== NULL
)
668 if (size
== search_len
) {
669 if (prefs
.word_mode
== WRAP
) /* Find last space */
670 next_line
= find_last_space(cur_line
, size
);
672 if (next_line
== NULL
)
673 next_line
= crop_at_width(cur_line
);
675 if (prefs
.word_mode
== WRAP
)
677 i
<WRAP_TRIM
&& isspace(next_line
[0]) && !BUFFER_OOB(next_line
);
682 if (prefs
.line_mode
== EXPAND
)
683 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
684 if (next_line
[0] == 0)
685 if (next_line
!= cur_line
)
686 return (unsigned char*) next_line
;
688 /* If next_line is pointing to a zero, increment it; i.e.,
689 leave the terminator at the end of cur_line. If pointing
690 to a hyphen, increment only if there is room to display
691 the hyphen on current line (won't apply in WIDE mode,
692 since it's guarenteed there won't be room). */
693 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
694 if (next_line
[0] == 0)/* ||
695 (next_line[0] == '-' && next_line-cur_line < draw_columns)) */
698 if (BUFFER_OOB(next_line
))
704 return (unsigned char*) next_line
;
707 static unsigned char* find_prev_line(const unsigned char* cur_line
)
709 const unsigned char *prev_line
= NULL
;
710 const unsigned char *p
;
712 if BUFFER_OOB(cur_line
)
715 /* To wrap consistently at the same places, we must
716 start with a known hard return, then work downwards.
717 We can either search backwards for a hard return,
718 or simply start wrapping downwards from top of buffer.
719 If current line is not near top of buffer, this is
720 a file with long lines (paragraphs). We would need to
721 read earlier sectors before we could decide how to
722 properly wrap the lines above the current line, but
723 it probably is not worth the disk access. Instead,
724 start with top of buffer and wrap down from there.
725 This may result in some lines wrapping at different
726 points from where they wrap when scrolling down.
727 If buffer is at top of file, start at top of buffer. */
729 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
))
730 prev_line
= p
= NULL
;
732 prev_line
= p
= find_last_feed(buffer
, cur_line
-buffer
-1);
733 /* Null means no line feeds in buffer above current line. */
735 if (prev_line
== NULL
)
736 if (BUFFER_BOF() || cur_line
- buffer
> READ_PREV_ZONE
)
737 prev_line
= p
= buffer
;
738 /* (else return NULL and read previous block) */
740 /* Wrap downwards until too far, then use the one before. */
741 while (p
< cur_line
&& p
!= NULL
) {
743 p
= find_next_line(prev_line
, NULL
);
746 if (BUFFER_OOB(prev_line
))
749 return (unsigned char*) prev_line
;
752 static void fill_buffer(long pos
, unsigned char* buf
, unsigned size
)
754 /* Read from file and preprocess the data */
755 /* To minimize disk access, always read on sector boundaries */
757 bool found_CR
= false;
759 rb
->lseek(fd
, pos
, SEEK_SET
);
760 numread
= rb
->read(fd
, buf
, size
);
761 rb
->button_clear_queue(); /* clear button queue */
763 for(i
= 0; i
< numread
; i
++) {
780 case 0: /* No break between case 0 and default, intentionally */
793 static int read_and_synch(int direction
)
795 /* Read next (or prev) block, and reposition global pointers. */
796 /* direction: 1 for down (i.e., further into file), -1 for up */
797 int move_size
, move_vector
, offset
;
798 unsigned char *fill_buf
;
800 if (direction
== -1) /* up */ {
801 move_size
= SMALL_BLOCK_SIZE
;
803 fill_buf
= TOP_SECTOR
;
804 rb
->memcpy(BOTTOM_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
805 rb
->memcpy(MID_SECTOR
, TOP_SECTOR
, SMALL_BLOCK_SIZE
);
808 if (prefs
.view_mode
== WIDE
) {
809 /* WIDE mode needs more buffer so we have to read smaller blocks */
810 move_size
= SMALL_BLOCK_SIZE
;
811 offset
= LARGE_BLOCK_SIZE
;
812 fill_buf
= BOTTOM_SECTOR
;
813 rb
->memcpy(TOP_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
814 rb
->memcpy(MID_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
817 move_size
= LARGE_BLOCK_SIZE
;
818 offset
= SMALL_BLOCK_SIZE
;
819 fill_buf
= MID_SECTOR
;
820 rb
->memcpy(TOP_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
823 move_vector
= direction
* move_size
;
824 screen_top_ptr
-= move_vector
;
825 file_pos
+= move_vector
;
826 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
827 fill_buffer(file_pos
+ offset
, fill_buf
, move_size
);
831 static void viewer_scroll_up(void)
835 p
= find_prev_line(screen_top_ptr
);
836 if (p
== NULL
&& !BUFFER_BOF()) {
838 p
= find_prev_line(screen_top_ptr
);
844 static void viewer_scroll_down(void)
846 if (next_screen_ptr
!= NULL
)
847 screen_top_ptr
= next_line_ptr
;
850 #ifdef HAVE_LCD_BITMAP
851 static void viewer_scrollbar(void) {
852 int items
, min_shown
, max_shown
;
854 items
= (int) file_size
; /* (SH1 int is same as long) */
855 min_shown
= (int) file_pos
+ (screen_top_ptr
- buffer
);
857 if (next_screen_ptr
== NULL
)
860 max_shown
= min_shown
+ (next_screen_ptr
- screen_top_ptr
);
862 rb
->gui_scrollbar_draw(rb
->screens
[SCREEN_MAIN
],0, 0, SCROLLBAR_WIDTH
-1,
863 LCD_HEIGHT
, items
, min_shown
, max_shown
, VERTICAL
);
867 static void viewer_draw(int col
)
869 int i
, j
, k
, line_len
, line_width
, resynch_move
, spaces
, left_col
=0;
870 int width
, extra_spaces
, indent_spaces
, spaces_per_word
;
871 bool multiple_spacing
, line_is_short
;
873 unsigned char *str
, *oldstr
;
874 unsigned char *line_begin
;
875 unsigned char *line_end
;
877 unsigned char scratch_buffer
[MAX_COLUMNS
+ 1];
878 unsigned char utf8_buffer
[MAX_COLUMNS
*4 + 1];
879 unsigned char *endptr
;
881 /* If col==-1 do all calculations but don't display */
883 #ifdef HAVE_LCD_BITMAP
884 left_col
= prefs
.need_scrollbar
? SCROLLBAR_WIDTH
:0;
888 rb
->lcd_clear_display();
891 line_begin
= line_end
= screen_top_ptr
;
893 for (i
= 0; i
< display_lines
; i
++) {
894 if (BUFFER_OOB(line_end
))
895 break; /* Happens after display last line at BUFFER_EOF() */
897 line_begin
= line_end
;
898 line_end
= find_next_line(line_begin
, &line_is_short
);
900 if (line_end
== NULL
) {
902 if (i
< display_lines
- 1 && !BUFFER_BOF()) {
904 rb
->lcd_clear_display();
906 for (; i
< display_lines
- 1; i
++)
909 line_begin
= line_end
= screen_top_ptr
;
914 line_end
= buffer_end
;
918 resynch_move
= read_and_synch(1); /* Read block & move ptrs */
919 line_begin
-= resynch_move
;
921 next_line_ptr
-= resynch_move
;
923 line_end
= find_next_line(line_begin
, NULL
);
924 if (line_end
== NULL
) /* Should not really happen */
928 line_len
= line_end
- line_begin
;
930 /* calculate line_len */
931 str
= oldstr
= line_begin
;
933 while (str
< line_end
) {
935 str
= crop_at_width(str
);
938 line_width
= j
*draw_columns
;
939 while (oldstr
< line_end
) {
940 oldstr
= get_ucs(oldstr
, &ch
);
941 line_width
+= glyph_width(ch
);
944 if (prefs
.line_mode
== JOIN
) {
945 if (line_begin
[0] == 0) {
947 if (prefs
.word_mode
== CHOP
)
952 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
953 if (k
== MAX_COLUMNS
)
963 scratch_buffer
[k
++] = ' ';
968 scratch_buffer
[k
++] = ' ';
969 if (k
== MAX_COLUMNS
- 1)
972 scratch_buffer
[k
++] = c
;
977 scratch_buffer
[k
] = 0;
978 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
979 prefs
.encoding
, draw_columns
/glyph_width('i'));
983 else if (prefs
.line_mode
== REFLOW
) {
984 if (line_begin
[0] == 0) {
986 if (prefs
.word_mode
== CHOP
)
993 if (!line_is_short
) {
994 multiple_spacing
= false;
996 for (str
= line_begin
; str
< line_end
; ) {
997 str
= get_ucs(str
, &ch
);
1001 if ((str
== line_begin
) && (prefs
.word_mode
==WRAP
))
1002 /* special case: indent the paragraph,
1003 * don't count spaces */
1004 indent_spaces
= par_indent_spaces
;
1005 else if (!multiple_spacing
)
1007 multiple_spacing
= true;
1010 multiple_spacing
= false;
1011 width
+= glyph_width(ch
);
1015 if (multiple_spacing
) spaces
--;
1018 /* total number of spaces to insert between words */
1019 extra_spaces
= (draw_columns
-width
)/glyph_width(' ')
1021 /* number of spaces between each word*/
1022 spaces_per_word
= extra_spaces
/ spaces
;
1023 /* number of words with n+1 spaces (to fill up) */
1024 extra_spaces
= extra_spaces
% spaces
;
1025 if (spaces_per_word
> 2) { /* too much spacing is awful */
1026 spaces_per_word
= 3;
1029 } else { /* this doesn't matter much... no spaces anyway */
1030 spaces_per_word
= extra_spaces
= 0;
1032 } else { /* end of a paragraph: don't fill line */
1033 spaces_per_word
= 1;
1037 multiple_spacing
= false;
1038 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
1039 if (k
== MAX_COLUMNS
)
1046 if (j
==0 && prefs
.word_mode
==WRAP
) { /* indent paragraph */
1047 for (j
=0; j
<par_indent_spaces
; j
++)
1048 scratch_buffer
[k
++] = ' ';
1051 else if (!multiple_spacing
) {
1052 for (width
= spaces
<extra_spaces
? -1:0; width
< spaces_per_word
; width
++)
1053 scratch_buffer
[k
++] = ' ';
1056 multiple_spacing
= true;
1059 scratch_buffer
[k
++] = c
;
1060 multiple_spacing
= false;
1066 scratch_buffer
[k
] = 0;
1067 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
1068 prefs
.encoding
, k
-col
);
1072 else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */
1074 if (line_width
> col
) {
1075 str
= oldstr
= line_begin
;
1078 while( (width
<draw_columns
) && (oldstr
<line_end
) )
1080 oldstr
= get_ucs(oldstr
, &ch
);
1082 k
-= glyph_width(ch
);
1083 line_begin
= oldstr
;
1085 width
+= glyph_width(ch
);
1089 if(prefs
.view_mode
==WIDE
)
1090 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1091 prefs
.encoding
, oldstr
-line_begin
);
1093 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1094 prefs
.encoding
, line_end
-line_begin
);
1098 if (col
!= -1 && line_width
> col
)
1099 #ifdef HAVE_LCD_BITMAP
1100 rb
->lcd_putsxy(left_col
, i
*pf
->height
, utf8_buffer
);
1102 rb
->lcd_puts(left_col
, i
, utf8_buffer
);
1104 if (line_width
> max_line_len
)
1105 max_line_len
= line_width
;
1108 next_line_ptr
= line_end
;
1110 next_screen_ptr
= line_end
;
1111 if (BUFFER_OOB(next_screen_ptr
))
1112 next_screen_ptr
= NULL
;
1114 #ifdef HAVE_LCD_BITMAP
1115 next_screen_to_draw_ptr
= prefs
.page_mode
==OVERLAP
? line_begin
: next_screen_ptr
;
1117 if (prefs
.need_scrollbar
)
1120 next_screen_to_draw_ptr
= next_screen_ptr
;
1127 static void viewer_top(void)
1129 /* Read top of file into buffer
1130 and point screen pointer to top */
1134 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1135 fill_buffer(0, buffer
, buffer_size
);
1138 screen_top_ptr
= buffer
;
1141 static void viewer_bottom(void)
1143 /* Read bottom of file into buffer
1144 and point screen pointer to bottom */
1147 if (file_size
> buffer_size
) {
1148 /* Find last buffer in file, round up to next sector boundary */
1149 last_sectors
= file_size
- buffer_size
+ SMALL_BLOCK_SIZE
;
1150 last_sectors
/= SMALL_BLOCK_SIZE
;
1151 last_sectors
*= SMALL_BLOCK_SIZE
;
1157 if (file_pos
!= last_sectors
)
1159 file_pos
= last_sectors
;
1160 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1161 fill_buffer(last_sectors
, buffer
, buffer_size
);
1164 screen_top_ptr
= buffer_end
-1;
1167 #ifdef HAVE_LCD_BITMAP
1168 static void init_need_scrollbar(void) {
1169 /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
1170 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
1172 prefs
.need_scrollbar
= NEED_SCROLLBAR();
1173 draw_columns
= prefs
.need_scrollbar
? display_columns
-SCROLLBAR_WIDTH
: display_columns
;
1174 par_indent_spaces
= draw_columns
/(5*glyph_width(' '));
1177 #define init_need_scrollbar()
1180 static bool viewer_init(void)
1182 #ifdef HAVE_LCD_BITMAP
1184 pf
= rb
->font_get(FONT_UI
);
1186 display_lines
= LCD_HEIGHT
/ pf
->height
;
1187 draw_columns
= display_columns
= LCD_WIDTH
;
1189 /* REAL fixed pitch :) all chars use up 1 cell */
1191 draw_columns
= display_columns
= 11;
1192 par_indent_spaces
= 2;
1195 fd
= rb
->open(file_name
, O_RDONLY
);
1199 file_size
= rb
->filesize(fd
);
1203 /* Init mac_text value used in processing buffer */
1209 static void viewer_default_settings(void)
1211 prefs
.word_mode
= WRAP
;
1212 prefs
.line_mode
= NORMAL
;
1213 prefs
.view_mode
= NARROW
;
1214 prefs
.scroll_mode
= PAGE
;
1215 #ifdef HAVE_LCD_BITMAP
1216 prefs
.page_mode
= NO_OVERLAP
;
1217 prefs
.scrollbar_mode
= SB_OFF
;
1219 prefs
.autoscroll_speed
= 1;
1220 /* Set codepage to system default */
1221 prefs
.encoding
= rb
->global_settings
->default_codepage
;
1224 static void viewer_load_settings(void) /* same name as global, but not the same file.. */
1227 struct bookmark_file_data
*data
;
1228 struct bookmarked_file_info this_bookmark
;
1230 /* read settings file */
1231 settings_fd
=rb
->open(SETTINGS_FILE
, O_RDONLY
);
1232 if ((settings_fd
>= 0) && (rb
->filesize(settings_fd
) == sizeof(struct preferences
)))
1234 rb
->read(settings_fd
, &prefs
, sizeof(struct preferences
));
1235 rb
->close(settings_fd
);
1239 /* load default settings if there is no settings file */
1240 viewer_default_settings();
1243 rb
->memcpy(&old_prefs
, &prefs
, sizeof(struct preferences
));
1245 data
= (struct bookmark_file_data
*)buffer
; /* grab the text buffer */
1246 data
->bookmarked_files_count
= 0;
1248 /* read bookmarks if file exists */
1249 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_RDONLY
);
1250 if (settings_fd
>= 0)
1252 /* figure out how many items to read */
1253 rb
->read(settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1254 if (data
->bookmarked_files_count
> MAX_BOOKMARKED_FILES
)
1255 data
->bookmarked_files_count
= MAX_BOOKMARKED_FILES
;
1256 rb
->read(settings_fd
, data
->bookmarks
,
1257 sizeof(struct bookmarked_file_info
) * data
->bookmarked_files_count
);
1258 rb
->close(settings_fd
);
1262 screen_top_ptr
= buffer
;
1264 /* check if current file is in list */
1265 for (i
=0; i
< data
->bookmarked_files_count
; i
++)
1267 if (!rb
->strcmp(file_name
, data
->bookmarks
[i
].filename
))
1269 int screen_pos
= data
->bookmarks
[i
].file_position
+ data
->bookmarks
[i
].top_ptr_pos
;
1270 int screen_top
= screen_pos
% buffer_size
;
1271 file_pos
= screen_pos
- screen_top
;
1272 screen_top_ptr
= buffer
+ screen_top
;
1277 this_bookmark
.file_position
= file_pos
;
1278 this_bookmark
.top_ptr_pos
= screen_top_ptr
- buffer
;
1280 rb
->memset(&this_bookmark
.filename
[0],0,MAX_PATH
);
1281 rb
->strcpy(this_bookmark
.filename
,file_name
);
1283 /* prevent potential slot overflow */
1284 if (i
>= data
->bookmarked_files_count
)
1286 if (i
< MAX_BOOKMARKED_FILES
)
1287 data
->bookmarked_files_count
++;
1289 i
= MAX_BOOKMARKED_FILES
-1;
1292 /* write bookmark file with spare slot in first position
1293 to be filled in by viewer_save_settings */
1294 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1295 if (settings_fd
>=0 )
1298 rb
->write (settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1300 /* write the current bookmark */
1301 rb
->write (settings_fd
, &this_bookmark
, sizeof(struct bookmarked_file_info
));
1303 /* write everything that was before this bookmark */
1304 rb
->write (settings_fd
, data
->bookmarks
, sizeof(struct bookmarked_file_info
)*i
);
1306 rb
->close(settings_fd
);
1309 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1311 if (BUFFER_OOB(screen_top_ptr
))
1313 screen_top_ptr
= buffer
;
1316 fill_buffer(file_pos
, buffer
, buffer_size
);
1318 /* remember the current position */
1319 start_position
= file_pos
+ screen_top_ptr
- buffer
;
1321 init_need_scrollbar();
1324 static void viewer_save_settings(void)/* same name as global, but not the same file.. */
1328 /* save the viewer settings if they have been changed */
1329 if (rb
->memcmp(&prefs
, &old_prefs
, sizeof(struct preferences
)))
1331 settings_fd
= rb
->creat(SETTINGS_FILE
); /* create the settings file */
1333 if (settings_fd
>= 0 )
1335 rb
->write (settings_fd
, &prefs
, sizeof(struct preferences
));
1336 rb
->close(settings_fd
);
1340 /* save the bookmark if the position has changed */
1341 if (file_pos
+ screen_top_ptr
- buffer
!= start_position
)
1343 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1345 if (settings_fd
>= 0 )
1347 struct bookmarked_file_info b
;
1348 b
.file_position
= file_pos
+ screen_top_ptr
- buffer
;
1349 b
.top_ptr_pos
= 0; /* this is only kept for legassy reasons */
1350 rb
->memset(&b
.filename
[0],0,MAX_PATH
);
1351 rb
->strcpy(b
.filename
,file_name
);
1352 rb
->lseek(settings_fd
,sizeof(signed int),SEEK_SET
);
1353 rb
->write (settings_fd
, &b
, sizeof(struct bookmarked_file_info
));
1354 rb
->close(settings_fd
);
1359 static void viewer_exit(void *parameter
)
1363 viewer_save_settings();
1367 static int col_limit(int col
)
1372 if (col
> max_line_len
- 2*glyph_width('o'))
1373 col
= max_line_len
- 2*glyph_width('o');
1378 /* settings helper functions */
1380 static bool encoding_setting(void)
1382 static struct opt_items names
[NUM_CODEPAGES
];
1385 for (idx
= 0; idx
< NUM_CODEPAGES
; idx
++)
1387 names
[idx
].string
= rb
->get_codepage_name(idx
);
1388 names
[idx
].voice_id
= -1;
1391 return rb
->set_option("Encoding", &prefs
.encoding
, INT
, names
,
1392 sizeof(names
) / sizeof(names
[0]), NULL
);
1395 static bool word_wrap_setting(void)
1397 static const struct opt_items names
[] = {
1399 {"Off (Chop Words)", -1},
1402 return rb
->set_option("Word Wrap", &prefs
.word_mode
, INT
,
1406 static bool line_mode_setting(void)
1408 static const struct opt_items names
[] = {
1411 {"Expand Lines", -1},
1412 #ifdef HAVE_LCD_BITMAP
1413 {"Reflow Lines", -1},
1417 return rb
->set_option("Line Mode", &prefs
.line_mode
, INT
, names
,
1418 sizeof(names
) / sizeof(names
[0]), NULL
);
1421 static bool view_mode_setting(void)
1423 static const struct opt_items names
[] = {
1424 {"No (Narrow)", -1},
1428 ret
= rb
->set_option("Wide View", &prefs
.view_mode
, INT
,
1430 if (prefs
.view_mode
== NARROW
)
1435 static bool scroll_mode_setting(void)
1437 static const struct opt_items names
[] = {
1438 {"Scroll by Page", -1},
1439 {"Scroll by Line", -1},
1442 return rb
->set_option("Scroll Mode", &prefs
.scroll_mode
, INT
,
1446 #ifdef HAVE_LCD_BITMAP
1447 static bool page_mode_setting(void)
1449 static const struct opt_items names
[] = {
1454 return rb
->set_option("Overlap Pages", &prefs
.page_mode
, INT
,
1458 static bool scrollbar_setting(void)
1460 static const struct opt_items names
[] = {
1465 return rb
->set_option("Show Scrollbar", &prefs
.scrollbar_mode
, INT
,
1470 static bool autoscroll_speed_setting(void)
1472 return rb
->set_int("Auto-scroll Speed", "", UNIT_INT
,
1473 &prefs
.autoscroll_speed
, NULL
, 1, 1, 10, NULL
);
1476 MENUITEM_FUNCTION(encoding_item
, 0, "Encoding", encoding_setting
,
1477 NULL
, NULL
, Icon_NOICON
);
1478 MENUITEM_FUNCTION(word_wrap_item
, 0, "Word Wrap", word_wrap_setting
,
1479 NULL
, NULL
, Icon_NOICON
);
1480 MENUITEM_FUNCTION(line_mode_item
, 0, "Line Mode", line_mode_setting
,
1481 NULL
, NULL
, Icon_NOICON
);
1482 MENUITEM_FUNCTION(view_mode_item
, 0, "Wide View", view_mode_setting
,
1483 NULL
, NULL
, Icon_NOICON
);
1484 #ifdef HAVE_LCD_BITMAP
1485 MENUITEM_FUNCTION(scrollbar_item
, 0, "Show Scrollbar", scrollbar_setting
,
1486 NULL
, NULL
, Icon_NOICON
);
1487 MENUITEM_FUNCTION(page_mode_item
, 0, "Overlap Pages", page_mode_setting
,
1488 NULL
, NULL
, Icon_NOICON
);
1490 MENUITEM_FUNCTION(scroll_mode_item
, 0, "Scroll Mode", scroll_mode_setting
,
1491 NULL
, NULL
, Icon_NOICON
);
1492 MENUITEM_FUNCTION(autoscroll_speed_item
, 0, "Auto-Scroll Speed",
1493 autoscroll_speed_setting
, NULL
, NULL
, Icon_NOICON
);
1494 MAKE_MENU(option_menu
, "Viewer Options", NULL
, Icon_NOICON
,
1495 &encoding_item
, &word_wrap_item
, &line_mode_item
, &view_mode_item
,
1496 #ifdef HAVE_LCD_BITMAP
1497 &scrollbar_item
, &page_mode_item
,
1499 &scroll_mode_item
, &autoscroll_speed_item
);
1501 static bool viewer_options_menu(void)
1504 result
= (rb
->do_menu(&option_menu
, NULL
, NULL
, false) == MENU_ATTACHED_USB
);
1506 #ifdef HAVE_LCD_BITMAP
1507 /* Show-scrollbar mode for current view-width mode */
1508 init_need_scrollbar();
1513 static void viewer_menu(void)
1516 MENUITEM_STRINGLIST(menu
, "Viewer Menu", NULL
,
1517 "Return", "Viewer Options",
1518 "Show Playback Menu", "Quit");
1520 result
= rb
->do_menu(&menu
, NULL
, NULL
, false);
1523 case 0: /* return */
1525 case 1: /* change settings */
1526 done
= viewer_options_menu();
1528 case 2: /* playback control */
1529 playback_control(NULL
);
1539 enum plugin_status
plugin_start(const void* file
)
1542 int lastbutton
= BUTTON_NONE
;
1543 bool autoscroll
= false;
1546 old_tick
= *rb
->current_tick
;
1548 /* get the plugin buffer */
1549 buffer
= rb
->plugin_get_buffer((size_t *)&buffer_size
);
1552 return PLUGIN_ERROR
;
1557 rb
->splash(HZ
, "Error opening file.");
1558 return PLUGIN_ERROR
;
1561 viewer_load_settings(); /* load the preferences and bookmark */
1564 rb
->lcd_set_backdrop(NULL
);
1573 if(old_tick
<= *rb
->current_tick
- (110-prefs
.autoscroll_speed
*10))
1575 viewer_scroll_down();
1577 old_tick
= *rb
->current_tick
;
1581 button
= rb
->button_get_w_tmo(HZ
/10);
1587 case VIEWER_AUTOSCROLL
:
1588 #ifdef VIEWER_AUTOSCROLL_PRE
1589 if (lastbutton
!= VIEWER_AUTOSCROLL_PRE
)
1592 autoscroll
= !autoscroll
;
1595 case VIEWER_PAGE_UP
:
1596 case VIEWER_PAGE_UP
| BUTTON_REPEAT
:
1597 if (prefs
.scroll_mode
== PAGE
)
1600 #ifdef HAVE_LCD_BITMAP
1601 for (i
= prefs
.page_mode
==OVERLAP
? 1:0; i
< display_lines
; i
++)
1603 for (i
= 0; i
< display_lines
; i
++)
1609 old_tick
= *rb
->current_tick
;
1613 case VIEWER_PAGE_DOWN
:
1614 case VIEWER_PAGE_DOWN
| BUTTON_REPEAT
:
1615 if (prefs
.scroll_mode
== PAGE
)
1618 if (next_screen_ptr
!= NULL
)
1619 screen_top_ptr
= next_screen_to_draw_ptr
;
1622 viewer_scroll_down();
1623 old_tick
= *rb
->current_tick
;
1627 case VIEWER_SCREEN_LEFT
:
1628 case VIEWER_SCREEN_LEFT
| BUTTON_REPEAT
:
1629 if (prefs
.view_mode
== WIDE
) {
1631 col
-= draw_columns
;
1632 col
= col_limit(col
);
1634 else { /* prefs.view_mode == NARROW */
1642 case VIEWER_SCREEN_RIGHT
:
1643 case VIEWER_SCREEN_RIGHT
| BUTTON_REPEAT
:
1644 if (prefs
.view_mode
== WIDE
) {
1646 col
+= draw_columns
;
1647 col
= col_limit(col
);
1649 else { /* prefs.view_mode == NARROW */
1650 /* Bottom of file */
1657 #ifdef VIEWER_LINE_UP
1658 case VIEWER_LINE_UP
:
1659 case VIEWER_LINE_UP
| BUTTON_REPEAT
:
1660 /* Scroll up one line */
1662 old_tick
= *rb
->current_tick
;
1666 case VIEWER_LINE_DOWN
:
1667 case VIEWER_LINE_DOWN
| BUTTON_REPEAT
:
1668 /* Scroll down one line */
1669 if (next_screen_ptr
!= NULL
)
1670 screen_top_ptr
= next_line_ptr
;
1671 old_tick
= *rb
->current_tick
;
1675 #ifdef VIEWER_COLUMN_LEFT
1676 case VIEWER_COLUMN_LEFT
:
1677 case VIEWER_COLUMN_LEFT
| BUTTON_REPEAT
:
1678 if (prefs
.view_mode
== WIDE
) {
1679 /* Scroll left one column */
1680 col
-= glyph_width('o');
1681 col
= col_limit(col
);
1686 case VIEWER_COLUMN_RIGHT
:
1687 case VIEWER_COLUMN_RIGHT
| BUTTON_REPEAT
:
1688 if (prefs
.view_mode
== WIDE
) {
1689 /* Scroll right one column */
1690 col
+= glyph_width('o');
1691 col
= col_limit(col
);
1697 #ifdef VIEWER_RC_QUIT
1698 case VIEWER_RC_QUIT
:
1706 if (rb
->default_event_handler_ex(button
, viewer_exit
, NULL
)
1707 == SYS_USB_CONNECTED
)
1708 return PLUGIN_USB_CONNECTED
;
1711 if (button
!= BUTTON_NONE
)
1713 lastbutton
= button
;