1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 Gilles Roux, 2003 Garrett Derner
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 #include "lib/playback_control.h"
27 #define SETTINGS_FILE VIEWERS_DIR "/viewer.dat" /* binary file, so dont use .cfg */
28 #define BOOKMARKS_FILE VIEWERS_DIR "/viewer_bookmarks.dat"
30 #define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */
31 #define MAX_COLUMNS 64 /* Max displayable string len (over-estimate) */
32 #define MAX_WIDTH 910 /* Max line length in WIDE mode */
33 #define READ_PREV_ZONE 910 /* Arbitrary number less than SMALL_BLOCK_SIZE */
34 #define SMALL_BLOCK_SIZE 0x1000 /* 4k: Smallest file chunk we will read */
35 #define LARGE_BLOCK_SIZE 0x2000 /* 8k: Preferable size of file chunk to read */
36 #define TOP_SECTOR buffer
37 #define MID_SECTOR (buffer + SMALL_BLOCK_SIZE)
38 #define BOTTOM_SECTOR (buffer + 2*(SMALL_BLOCK_SIZE))
39 #undef SCROLLBAR_WIDTH
40 #define SCROLLBAR_WIDTH rb->global_settings->scrollbar_width
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 == COWON_D2_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 /* Philips SA9200 keys */
327 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
328 #define VIEWER_QUIT BUTTON_POWER
329 #define VIEWER_PAGE_UP BUTTON_UP
330 #define VIEWER_PAGE_DOWN BUTTON_DOWN
331 #define VIEWER_SCREEN_LEFT BUTTON_PREV
332 #define VIEWER_SCREEN_RIGHT BUTTON_NEXT
333 #define VIEWER_MENU BUTTON_MENU
334 #define VIEWER_AUTOSCROLL BUTTON_PLAY
336 /* Onda VX747 keys */
337 #elif CONFIG_KEYPAD == ONDAVX747_PAD
338 #define VIEWER_QUIT BUTTON_POWER
339 #define VIEWER_MENU BUTTON_MENU
341 /* Onda VX777 keys */
342 #elif CONFIG_KEYPAD == ONDAVX777_PAD
343 #define VIEWER_QUIT BUTTON_POWER
345 /* SAMSUNG YH-820 / YH-920 / YH-925 keys */
346 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
347 #define VIEWER_QUIT BUTTON_REC
348 #define VIEWER_PAGE_UP BUTTON_UP
349 #define VIEWER_PAGE_DOWN BUTTON_DOWN
350 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
351 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
352 #define VIEWER_MENU BUTTON_PLAY
353 #define VIEWER_AUTOSCROLL BUTTON_REW
355 /* Packard Bell Vibe 500 keys */
356 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
357 #define VIEWER_QUIT BUTTON_REC
358 #define VIEWER_PAGE_UP BUTTON_OK
359 #define VIEWER_PAGE_DOWN BUTTON_CANCEL
360 #define VIEWER_LINE_UP BUTTON_UP
361 #define VIEWER_LINE_DOWN BUTTON_DOWN
362 #define VIEWER_SCREEN_LEFT BUTTON_PREV
363 #define VIEWER_SCREEN_RIGHT BUTTON_NEXT
364 #define VIEWER_MENU BUTTON_MENU
365 #define VIEWER_AUTOSCROLL BUTTON_PLAY
368 #error No keymap defined!
371 #ifdef HAVE_TOUCHSCREEN
373 #define VIEWER_QUIT BUTTON_TOPLEFT
375 #ifndef VIEWER_PAGE_UP
376 #define VIEWER_PAGE_UP BUTTON_TOPMIDDLE
378 #ifndef VIEWER_PAGE_DOWN
379 #define VIEWER_PAGE_DOWN BUTTON_BOTTOMMIDDLE
381 #ifndef VIEWER_SCREEN_LEFT
382 #define VIEWER_SCREEN_LEFT BUTTON_MIDLEFT
384 #ifndef VIEWER_SCREEN_RIGHT
385 #define VIEWER_SCREEN_RIGHT BUTTON_MIDRIGHT
388 #define VIEWER_MENU BUTTON_TOPRIGHT
390 #ifndef VIEWER_AUTOSCROLL
391 #define VIEWER_AUTOSCROLL BUTTON_CENTER
395 /* stuff for the bookmarking */
396 struct bookmarked_file_info
{
399 char filename
[MAX_PATH
];
402 struct bookmark_file_data
{
403 signed int bookmarked_files_count
;
404 struct bookmarked_file_info bookmarks
[];
417 REFLOW
, /* won't be set on charcell LCD, must be last */
425 enum codepages encoding
;
427 #ifdef HAVE_LCD_BITMAP
438 #endif /* HAVE_LCD_BITMAP */
445 int autoscroll_speed
;
448 struct preferences prefs
;
449 struct preferences old_prefs
;
451 static unsigned char *buffer
;
452 static long buffer_size
;
453 static unsigned char line_break
[] = {0,0x20,9,0xB,0xC,'-'};
454 static int display_columns
; /* number of (pixel) columns on the display */
455 static int display_lines
; /* number of lines on the display */
456 static int draw_columns
; /* number of (pixel) columns available for text */
457 static int par_indent_spaces
; /* number of spaces to indent first paragraph */
459 static const char *file_name
;
460 static long file_size
;
461 static long start_position
; /* position in the file after the viewer is started */
462 static bool mac_text
;
463 static long file_pos
; /* Position of the top of the buffer in the file */
464 static unsigned char *buffer_end
; /*Set to BUFFER_END() when file_pos changes*/
465 static int max_line_len
;
466 static unsigned char *screen_top_ptr
;
467 static unsigned char *next_screen_ptr
;
468 static unsigned char *next_screen_to_draw_ptr
;
469 static unsigned char *next_line_ptr
;
470 #ifdef HAVE_LCD_BITMAP
471 static struct font
*pf
;
475 int glyph_width(int ch
)
480 #ifdef HAVE_LCD_BITMAP
481 return rb
->font_get_width(pf
, ch
);
487 unsigned char* get_ucs(const unsigned char* str
, unsigned short* ch
)
489 unsigned char utf8_tmp
[6];
492 if (prefs
.encoding
== UTF_8
)
493 return (unsigned char*)rb
->utf8decode(str
, ch
);
495 count
= BUFFER_OOB(str
+2)? 1:2;
496 rb
->iso_decode(str
, utf8_tmp
, prefs
.encoding
, count
);
497 rb
->utf8decode(utf8_tmp
, ch
);
499 #ifdef HAVE_LCD_BITMAP
500 if (prefs
.encoding
>= SJIS
&& *str
>= 0x80
501 && !(prefs
.encoding
== SJIS
&& *str
> 0xA0 && *str
< 0xE0))
502 return (unsigned char*)str
+2;
505 return (unsigned char*)str
+1;
511 #define ADVANCE_COUNTERS(c) { width += glyph_width(c); k++; }
512 #define LINE_IS_FULL ((k>=MAX_COLUMNS-1) ||( width >= draw_columns))
513 #define LINE_IS_NOT_FULL ((k<MAX_COLUMNS-1) &&( width < draw_columns))
514 static unsigned char* crop_at_width(const unsigned char* p
)
518 const unsigned char *oldp
= p
;
522 while (LINE_IS_NOT_FULL
) {
525 ADVANCE_COUNTERS(ch
);
528 return (unsigned char*)oldp
;
531 static unsigned char* find_first_feed(const unsigned char* p
, int size
)
535 for (i
=0; i
< size
; i
++)
537 return (unsigned char*) p
+i
;
542 static unsigned char* find_last_feed(const unsigned char* p
, int size
)
546 for (i
=size
-1; i
>=0; i
--)
548 return (unsigned char*) p
+i
;
553 static unsigned char* find_last_space(const unsigned char* p
, int size
)
557 k
= (prefs
.line_mode
==JOIN
) || (prefs
.line_mode
==REFLOW
) ? 0:1;
559 if (!BUFFER_OOB(&p
[size
]))
560 for (j
=k
; j
< ((int) sizeof(line_break
)) - 1; j
++)
561 if (p
[size
] == line_break
[j
])
562 return (unsigned char*) p
+size
;
564 for (i
=size
-1; i
>=0; i
--)
565 for (j
=k
; j
< (int) sizeof(line_break
); j
++)
567 if (!((p
[i
] == '-') && (prefs
.word_mode
== WRAP
)))
568 if (p
[i
] == line_break
[j
])
569 return (unsigned char*) p
+i
;
575 static unsigned char* find_next_line(const unsigned char* cur_line
, bool *is_short
)
577 const unsigned char *next_line
= NULL
;
578 int size
, i
, j
, k
, width
, search_len
, spaces
, newlines
;
582 if (is_short
!= NULL
)
585 if BUFFER_OOB(cur_line
)
588 if (prefs
.view_mode
== WIDE
) {
589 search_len
= MAX_WIDTH
;
591 else { /* prefs.view_mode == NARROW */
592 search_len
= crop_at_width(cur_line
) - cur_line
;
595 size
= BUFFER_OOB(cur_line
+search_len
) ? buffer_end
-cur_line
: search_len
;
597 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
)) {
598 /* Need to scan ahead and possibly increase search_len and size,
599 or possibly set next_line at second hard return in a row. */
602 for (j
=k
=width
=spaces
=newlines
=0; ; j
++) {
603 if (BUFFER_OOB(cur_line
+j
))
606 size
= search_len
= j
;
613 if (prefs
.line_mode
== REFLOW
) {
616 next_line
= cur_line
+ size
;
617 return (unsigned char*) next_line
;
619 if (j
==0) /* i=1 is intentional */
620 for (i
=0; i
<par_indent_spaces
; i
++)
621 ADVANCE_COUNTERS(' ');
623 if (!first_chars
) spaces
++;
629 next_line
= cur_line
+ size
- spaces
;
630 if (next_line
!= cur_line
)
631 return (unsigned char*) next_line
;
637 if (BUFFER_OOB(cur_line
+size
) || size
> 2*search_len
)
640 spaces
= first_chars
? 0:1;
644 if (prefs
.line_mode
==JOIN
|| newlines
>0) {
647 ADVANCE_COUNTERS(' ');
649 size
= search_len
= j
;
655 /* REFLOW, multiple spaces between words: count only
656 * one. If more are needed, they will be added
660 ADVANCE_COUNTERS(' ');
662 size
= search_len
= j
;
673 /* find first hard return */
674 next_line
= find_first_feed(cur_line
, size
);
677 if (next_line
== NULL
)
678 if (size
== search_len
) {
679 if (prefs
.word_mode
== WRAP
) /* Find last space */
680 next_line
= find_last_space(cur_line
, size
);
682 if (next_line
== NULL
)
683 next_line
= crop_at_width(cur_line
);
685 if (prefs
.word_mode
== WRAP
)
687 i
<WRAP_TRIM
&& isspace(next_line
[0]) && !BUFFER_OOB(next_line
);
692 if (prefs
.line_mode
== EXPAND
)
693 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
694 if (next_line
[0] == 0)
695 if (next_line
!= cur_line
)
696 return (unsigned char*) next_line
;
698 /* If next_line is pointing to a zero, increment it; i.e.,
699 leave the terminator at the end of cur_line. If pointing
700 to a hyphen, increment only if there is room to display
701 the hyphen on current line (won't apply in WIDE mode,
702 since it's guarenteed there won't be room). */
703 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
704 if (next_line
[0] == 0)/* ||
705 (next_line[0] == '-' && next_line-cur_line < draw_columns)) */
708 if (BUFFER_OOB(next_line
))
714 return (unsigned char*) next_line
;
717 static unsigned char* find_prev_line(const unsigned char* cur_line
)
719 const unsigned char *prev_line
= NULL
;
720 const unsigned char *p
;
722 if BUFFER_OOB(cur_line
)
725 /* To wrap consistently at the same places, we must
726 start with a known hard return, then work downwards.
727 We can either search backwards for a hard return,
728 or simply start wrapping downwards from top of buffer.
729 If current line is not near top of buffer, this is
730 a file with long lines (paragraphs). We would need to
731 read earlier sectors before we could decide how to
732 properly wrap the lines above the current line, but
733 it probably is not worth the disk access. Instead,
734 start with top of buffer and wrap down from there.
735 This may result in some lines wrapping at different
736 points from where they wrap when scrolling down.
737 If buffer is at top of file, start at top of buffer. */
739 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
))
740 prev_line
= p
= NULL
;
742 prev_line
= p
= find_last_feed(buffer
, cur_line
-buffer
-1);
743 /* Null means no line feeds in buffer above current line. */
745 if (prev_line
== NULL
)
746 if (BUFFER_BOF() || cur_line
- buffer
> READ_PREV_ZONE
)
747 prev_line
= p
= buffer
;
748 /* (else return NULL and read previous block) */
750 /* Wrap downwards until too far, then use the one before. */
751 while (p
< cur_line
&& p
!= NULL
) {
753 p
= find_next_line(prev_line
, NULL
);
756 if (BUFFER_OOB(prev_line
))
759 return (unsigned char*) prev_line
;
762 static void fill_buffer(long pos
, unsigned char* buf
, unsigned size
)
764 /* Read from file and preprocess the data */
765 /* To minimize disk access, always read on sector boundaries */
767 bool found_CR
= false;
769 rb
->lseek(fd
, pos
, SEEK_SET
);
770 numread
= rb
->read(fd
, buf
, size
);
771 rb
->button_clear_queue(); /* clear button queue */
773 for(i
= 0; i
< numread
; i
++) {
790 case 0: /* No break between case 0 and default, intentionally */
803 static int read_and_synch(int direction
)
805 /* Read next (or prev) block, and reposition global pointers. */
806 /* direction: 1 for down (i.e., further into file), -1 for up */
807 int move_size
, move_vector
, offset
;
808 unsigned char *fill_buf
;
810 if (direction
== -1) /* up */ {
811 move_size
= SMALL_BLOCK_SIZE
;
813 fill_buf
= TOP_SECTOR
;
814 rb
->memcpy(BOTTOM_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
815 rb
->memcpy(MID_SECTOR
, TOP_SECTOR
, SMALL_BLOCK_SIZE
);
818 if (prefs
.view_mode
== WIDE
) {
819 /* WIDE mode needs more buffer so we have to read smaller blocks */
820 move_size
= SMALL_BLOCK_SIZE
;
821 offset
= LARGE_BLOCK_SIZE
;
822 fill_buf
= BOTTOM_SECTOR
;
823 rb
->memcpy(TOP_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
824 rb
->memcpy(MID_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
827 move_size
= LARGE_BLOCK_SIZE
;
828 offset
= SMALL_BLOCK_SIZE
;
829 fill_buf
= MID_SECTOR
;
830 rb
->memcpy(TOP_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
833 move_vector
= direction
* move_size
;
834 screen_top_ptr
-= move_vector
;
835 file_pos
+= move_vector
;
836 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
837 fill_buffer(file_pos
+ offset
, fill_buf
, move_size
);
841 static void viewer_scroll_up(void)
845 p
= find_prev_line(screen_top_ptr
);
846 if (p
== NULL
&& !BUFFER_BOF()) {
848 p
= find_prev_line(screen_top_ptr
);
854 static void viewer_scroll_down(void)
856 if (next_screen_ptr
!= NULL
)
857 screen_top_ptr
= next_line_ptr
;
860 #ifdef HAVE_LCD_BITMAP
861 static void viewer_scrollbar(void) {
862 int items
, min_shown
, max_shown
;
864 items
= (int) file_size
; /* (SH1 int is same as long) */
865 min_shown
= (int) file_pos
+ (screen_top_ptr
- buffer
);
867 if (next_screen_ptr
== NULL
)
870 max_shown
= min_shown
+ (next_screen_ptr
- screen_top_ptr
);
872 rb
->gui_scrollbar_draw(rb
->screens
[SCREEN_MAIN
],0, 0, SCROLLBAR_WIDTH
-1,
873 LCD_HEIGHT
, items
, min_shown
, max_shown
, VERTICAL
);
877 static void viewer_draw(int col
)
879 int i
, j
, k
, line_len
, line_width
, resynch_move
, spaces
, left_col
=0;
880 int width
, extra_spaces
, indent_spaces
, spaces_per_word
;
881 bool multiple_spacing
, line_is_short
;
883 unsigned char *str
, *oldstr
;
884 unsigned char *line_begin
;
885 unsigned char *line_end
;
887 unsigned char scratch_buffer
[MAX_COLUMNS
+ 1];
888 unsigned char utf8_buffer
[MAX_COLUMNS
*4 + 1];
889 unsigned char *endptr
;
891 /* If col==-1 do all calculations but don't display */
893 #ifdef HAVE_LCD_BITMAP
894 left_col
= prefs
.need_scrollbar
? SCROLLBAR_WIDTH
:0;
898 rb
->lcd_clear_display();
901 line_begin
= line_end
= screen_top_ptr
;
903 for (i
= 0; i
< display_lines
; i
++) {
904 if (BUFFER_OOB(line_end
))
905 break; /* Happens after display last line at BUFFER_EOF() */
907 line_begin
= line_end
;
908 line_end
= find_next_line(line_begin
, &line_is_short
);
910 if (line_end
== NULL
) {
912 if (i
< display_lines
- 1 && !BUFFER_BOF()) {
914 rb
->lcd_clear_display();
916 for (; i
< display_lines
- 1; i
++)
919 line_begin
= line_end
= screen_top_ptr
;
924 line_end
= buffer_end
;
928 resynch_move
= read_and_synch(1); /* Read block & move ptrs */
929 line_begin
-= resynch_move
;
931 next_line_ptr
-= resynch_move
;
933 line_end
= find_next_line(line_begin
, NULL
);
934 if (line_end
== NULL
) /* Should not really happen */
938 line_len
= line_end
- line_begin
;
940 /* calculate line_len */
941 str
= oldstr
= line_begin
;
943 while (str
< line_end
) {
945 str
= crop_at_width(str
);
948 line_width
= j
*draw_columns
;
949 while (oldstr
< line_end
) {
950 oldstr
= get_ucs(oldstr
, &ch
);
951 line_width
+= glyph_width(ch
);
954 if (prefs
.line_mode
== JOIN
) {
955 if (line_begin
[0] == 0) {
957 if (prefs
.word_mode
== CHOP
)
962 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
963 if (k
== MAX_COLUMNS
)
973 scratch_buffer
[k
++] = ' ';
978 scratch_buffer
[k
++] = ' ';
979 if (k
== MAX_COLUMNS
- 1)
982 scratch_buffer
[k
++] = c
;
987 scratch_buffer
[k
] = 0;
988 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
989 prefs
.encoding
, draw_columns
/glyph_width('i'));
993 else if (prefs
.line_mode
== REFLOW
) {
994 if (line_begin
[0] == 0) {
996 if (prefs
.word_mode
== CHOP
)
1003 if (!line_is_short
) {
1004 multiple_spacing
= false;
1006 for (str
= line_begin
; str
< line_end
; ) {
1007 str
= get_ucs(str
, &ch
);
1011 if ((str
== line_begin
) && (prefs
.word_mode
==WRAP
))
1012 /* special case: indent the paragraph,
1013 * don't count spaces */
1014 indent_spaces
= par_indent_spaces
;
1015 else if (!multiple_spacing
)
1017 multiple_spacing
= true;
1020 multiple_spacing
= false;
1021 width
+= glyph_width(ch
);
1025 if (multiple_spacing
) spaces
--;
1028 /* total number of spaces to insert between words */
1029 extra_spaces
= (draw_columns
-width
)/glyph_width(' ')
1031 /* number of spaces between each word*/
1032 spaces_per_word
= extra_spaces
/ spaces
;
1033 /* number of words with n+1 spaces (to fill up) */
1034 extra_spaces
= extra_spaces
% spaces
;
1035 if (spaces_per_word
> 2) { /* too much spacing is awful */
1036 spaces_per_word
= 3;
1039 } else { /* this doesn't matter much... no spaces anyway */
1040 spaces_per_word
= extra_spaces
= 0;
1042 } else { /* end of a paragraph: don't fill line */
1043 spaces_per_word
= 1;
1047 multiple_spacing
= false;
1048 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
1049 if (k
== MAX_COLUMNS
)
1056 if (j
==0 && prefs
.word_mode
==WRAP
) { /* indent paragraph */
1057 for (j
=0; j
<par_indent_spaces
; j
++)
1058 scratch_buffer
[k
++] = ' ';
1061 else if (!multiple_spacing
) {
1062 for (width
= spaces
<extra_spaces
? -1:0; width
< spaces_per_word
; width
++)
1063 scratch_buffer
[k
++] = ' ';
1066 multiple_spacing
= true;
1069 scratch_buffer
[k
++] = c
;
1070 multiple_spacing
= false;
1076 scratch_buffer
[k
] = 0;
1077 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
1078 prefs
.encoding
, k
-col
);
1082 else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */
1084 if (line_width
> col
) {
1085 str
= oldstr
= line_begin
;
1088 while( (width
<draw_columns
) && (oldstr
<line_end
) )
1090 oldstr
= get_ucs(oldstr
, &ch
);
1092 k
-= glyph_width(ch
);
1093 line_begin
= oldstr
;
1095 width
+= glyph_width(ch
);
1099 if(prefs
.view_mode
==WIDE
)
1100 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1101 prefs
.encoding
, oldstr
-line_begin
);
1103 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1104 prefs
.encoding
, line_end
-line_begin
);
1108 if (col
!= -1 && line_width
> col
)
1109 #ifdef HAVE_LCD_BITMAP
1110 rb
->lcd_putsxy(left_col
, i
*pf
->height
, utf8_buffer
);
1112 rb
->lcd_puts(left_col
, i
, utf8_buffer
);
1114 if (line_width
> max_line_len
)
1115 max_line_len
= line_width
;
1118 next_line_ptr
= line_end
;
1120 next_screen_ptr
= line_end
;
1121 if (BUFFER_OOB(next_screen_ptr
))
1122 next_screen_ptr
= NULL
;
1124 #ifdef HAVE_LCD_BITMAP
1125 next_screen_to_draw_ptr
= prefs
.page_mode
==OVERLAP
? line_begin
: next_screen_ptr
;
1127 if (prefs
.need_scrollbar
)
1130 next_screen_to_draw_ptr
= next_screen_ptr
;
1137 static void viewer_top(void)
1139 /* Read top of file into buffer
1140 and point screen pointer to top */
1144 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1145 fill_buffer(0, buffer
, buffer_size
);
1148 screen_top_ptr
= buffer
;
1151 static void viewer_bottom(void)
1153 /* Read bottom of file into buffer
1154 and point screen pointer to bottom */
1157 if (file_size
> buffer_size
) {
1158 /* Find last buffer in file, round up to next sector boundary */
1159 last_sectors
= file_size
- buffer_size
+ SMALL_BLOCK_SIZE
;
1160 last_sectors
/= SMALL_BLOCK_SIZE
;
1161 last_sectors
*= SMALL_BLOCK_SIZE
;
1167 if (file_pos
!= last_sectors
)
1169 file_pos
= last_sectors
;
1170 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1171 fill_buffer(last_sectors
, buffer
, buffer_size
);
1174 screen_top_ptr
= buffer_end
-1;
1177 #ifdef HAVE_LCD_BITMAP
1178 static void init_need_scrollbar(void) {
1179 /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
1180 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
1182 prefs
.need_scrollbar
= NEED_SCROLLBAR();
1183 draw_columns
= prefs
.need_scrollbar
? display_columns
-SCROLLBAR_WIDTH
: display_columns
;
1184 par_indent_spaces
= draw_columns
/(5*glyph_width(' '));
1187 #define init_need_scrollbar()
1190 static bool viewer_init(void)
1192 #ifdef HAVE_LCD_BITMAP
1194 pf
= rb
->font_get(FONT_UI
);
1196 display_lines
= LCD_HEIGHT
/ pf
->height
;
1197 draw_columns
= display_columns
= LCD_WIDTH
;
1199 /* REAL fixed pitch :) all chars use up 1 cell */
1201 draw_columns
= display_columns
= 11;
1202 par_indent_spaces
= 2;
1205 fd
= rb
->open(file_name
, O_RDONLY
);
1209 file_size
= rb
->filesize(fd
);
1213 /* Init mac_text value used in processing buffer */
1219 static void viewer_default_settings(void)
1221 prefs
.word_mode
= WRAP
;
1222 prefs
.line_mode
= NORMAL
;
1223 prefs
.view_mode
= NARROW
;
1224 prefs
.scroll_mode
= PAGE
;
1225 #ifdef HAVE_LCD_BITMAP
1226 prefs
.page_mode
= NO_OVERLAP
;
1227 prefs
.scrollbar_mode
= SB_OFF
;
1229 prefs
.autoscroll_speed
= 1;
1230 /* Set codepage to system default */
1231 prefs
.encoding
= rb
->global_settings
->default_codepage
;
1234 static void viewer_load_settings(void) /* same name as global, but not the same file.. */
1237 struct bookmark_file_data
*data
;
1238 struct bookmarked_file_info this_bookmark
;
1240 /* read settings file */
1241 settings_fd
=rb
->open(SETTINGS_FILE
, O_RDONLY
);
1242 if ((settings_fd
>= 0) && (rb
->filesize(settings_fd
) == sizeof(struct preferences
)))
1244 rb
->read(settings_fd
, &prefs
, sizeof(struct preferences
));
1245 rb
->close(settings_fd
);
1249 /* load default settings if there is no settings file */
1250 viewer_default_settings();
1253 rb
->memcpy(&old_prefs
, &prefs
, sizeof(struct preferences
));
1255 data
= (struct bookmark_file_data
*)buffer
; /* grab the text buffer */
1256 data
->bookmarked_files_count
= 0;
1258 /* read bookmarks if file exists */
1259 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_RDONLY
);
1260 if (settings_fd
>= 0)
1262 /* figure out how many items to read */
1263 rb
->read(settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1264 if (data
->bookmarked_files_count
> MAX_BOOKMARKED_FILES
)
1265 data
->bookmarked_files_count
= MAX_BOOKMARKED_FILES
;
1266 rb
->read(settings_fd
, data
->bookmarks
,
1267 sizeof(struct bookmarked_file_info
) * data
->bookmarked_files_count
);
1268 rb
->close(settings_fd
);
1272 screen_top_ptr
= buffer
;
1274 /* check if current file is in list */
1275 for (i
=0; i
< data
->bookmarked_files_count
; i
++)
1277 if (!rb
->strcmp(file_name
, data
->bookmarks
[i
].filename
))
1279 int screen_pos
= data
->bookmarks
[i
].file_position
+ data
->bookmarks
[i
].top_ptr_pos
;
1280 int screen_top
= screen_pos
% buffer_size
;
1281 file_pos
= screen_pos
- screen_top
;
1282 screen_top_ptr
= buffer
+ screen_top
;
1287 this_bookmark
.file_position
= file_pos
;
1288 this_bookmark
.top_ptr_pos
= screen_top_ptr
- buffer
;
1290 rb
->memset(&this_bookmark
.filename
[0],0,MAX_PATH
);
1291 rb
->strcpy(this_bookmark
.filename
,file_name
);
1293 /* prevent potential slot overflow */
1294 if (i
>= data
->bookmarked_files_count
)
1296 if (i
< MAX_BOOKMARKED_FILES
)
1297 data
->bookmarked_files_count
++;
1299 i
= MAX_BOOKMARKED_FILES
-1;
1302 /* write bookmark file with spare slot in first position
1303 to be filled in by viewer_save_settings */
1304 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1305 if (settings_fd
>=0 )
1308 rb
->write (settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1310 /* write the current bookmark */
1311 rb
->write (settings_fd
, &this_bookmark
, sizeof(struct bookmarked_file_info
));
1313 /* write everything that was before this bookmark */
1314 rb
->write (settings_fd
, data
->bookmarks
, sizeof(struct bookmarked_file_info
)*i
);
1316 rb
->close(settings_fd
);
1319 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1321 if (BUFFER_OOB(screen_top_ptr
))
1323 screen_top_ptr
= buffer
;
1326 fill_buffer(file_pos
, buffer
, buffer_size
);
1328 /* remember the current position */
1329 start_position
= file_pos
+ screen_top_ptr
- buffer
;
1331 init_need_scrollbar();
1334 static void viewer_save_settings(void)/* same name as global, but not the same file.. */
1338 /* save the viewer settings if they have been changed */
1339 if (rb
->memcmp(&prefs
, &old_prefs
, sizeof(struct preferences
)))
1341 settings_fd
= rb
->creat(SETTINGS_FILE
); /* create the settings file */
1343 if (settings_fd
>= 0 )
1345 rb
->write (settings_fd
, &prefs
, sizeof(struct preferences
));
1346 rb
->close(settings_fd
);
1350 /* save the bookmark if the position has changed */
1351 if (file_pos
+ screen_top_ptr
- buffer
!= start_position
)
1353 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1355 if (settings_fd
>= 0 )
1357 struct bookmarked_file_info b
;
1358 b
.file_position
= file_pos
+ screen_top_ptr
- buffer
;
1359 b
.top_ptr_pos
= 0; /* this is only kept for legassy reasons */
1360 rb
->memset(&b
.filename
[0],0,MAX_PATH
);
1361 rb
->strcpy(b
.filename
,file_name
);
1362 rb
->lseek(settings_fd
,sizeof(signed int),SEEK_SET
);
1363 rb
->write (settings_fd
, &b
, sizeof(struct bookmarked_file_info
));
1364 rb
->close(settings_fd
);
1369 static void viewer_exit(void *parameter
)
1373 viewer_save_settings();
1377 static int col_limit(int col
)
1382 if (col
> max_line_len
- 2*glyph_width('o'))
1383 col
= max_line_len
- 2*glyph_width('o');
1388 /* settings helper functions */
1390 static bool encoding_setting(void)
1392 static struct opt_items names
[NUM_CODEPAGES
];
1395 for (idx
= 0; idx
< NUM_CODEPAGES
; idx
++)
1397 names
[idx
].string
= rb
->get_codepage_name(idx
);
1398 names
[idx
].voice_id
= -1;
1401 return rb
->set_option("Encoding", &prefs
.encoding
, INT
, names
,
1402 sizeof(names
) / sizeof(names
[0]), NULL
);
1405 static bool word_wrap_setting(void)
1407 static const struct opt_items names
[] = {
1409 {"Off (Chop Words)", -1},
1412 return rb
->set_option("Word Wrap", &prefs
.word_mode
, INT
,
1416 static bool line_mode_setting(void)
1418 static const struct opt_items names
[] = {
1421 {"Expand Lines", -1},
1422 #ifdef HAVE_LCD_BITMAP
1423 {"Reflow Lines", -1},
1427 return rb
->set_option("Line Mode", &prefs
.line_mode
, INT
, names
,
1428 sizeof(names
) / sizeof(names
[0]), NULL
);
1431 static bool view_mode_setting(void)
1433 static const struct opt_items names
[] = {
1434 {"No (Narrow)", -1},
1438 ret
= rb
->set_option("Wide View", &prefs
.view_mode
, INT
,
1440 if (prefs
.view_mode
== NARROW
)
1445 static bool scroll_mode_setting(void)
1447 static const struct opt_items names
[] = {
1448 {"Scroll by Page", -1},
1449 {"Scroll by Line", -1},
1452 return rb
->set_option("Scroll Mode", &prefs
.scroll_mode
, INT
,
1456 #ifdef HAVE_LCD_BITMAP
1457 static bool page_mode_setting(void)
1459 static const struct opt_items names
[] = {
1464 return rb
->set_option("Overlap Pages", &prefs
.page_mode
, INT
,
1468 static bool scrollbar_setting(void)
1470 static const struct opt_items names
[] = {
1475 return rb
->set_option("Show Scrollbar", &prefs
.scrollbar_mode
, INT
,
1480 static bool autoscroll_speed_setting(void)
1482 return rb
->set_int("Auto-scroll Speed", "", UNIT_INT
,
1483 &prefs
.autoscroll_speed
, NULL
, 1, 1, 10, NULL
);
1486 MENUITEM_FUNCTION(encoding_item
, 0, "Encoding", encoding_setting
,
1487 NULL
, NULL
, Icon_NOICON
);
1488 MENUITEM_FUNCTION(word_wrap_item
, 0, "Word Wrap", word_wrap_setting
,
1489 NULL
, NULL
, Icon_NOICON
);
1490 MENUITEM_FUNCTION(line_mode_item
, 0, "Line Mode", line_mode_setting
,
1491 NULL
, NULL
, Icon_NOICON
);
1492 MENUITEM_FUNCTION(view_mode_item
, 0, "Wide View", view_mode_setting
,
1493 NULL
, NULL
, Icon_NOICON
);
1494 #ifdef HAVE_LCD_BITMAP
1495 MENUITEM_FUNCTION(scrollbar_item
, 0, "Show Scrollbar", scrollbar_setting
,
1496 NULL
, NULL
, Icon_NOICON
);
1497 MENUITEM_FUNCTION(page_mode_item
, 0, "Overlap Pages", page_mode_setting
,
1498 NULL
, NULL
, Icon_NOICON
);
1500 MENUITEM_FUNCTION(scroll_mode_item
, 0, "Scroll Mode", scroll_mode_setting
,
1501 NULL
, NULL
, Icon_NOICON
);
1502 MENUITEM_FUNCTION(autoscroll_speed_item
, 0, "Auto-Scroll Speed",
1503 autoscroll_speed_setting
, NULL
, NULL
, Icon_NOICON
);
1504 MAKE_MENU(option_menu
, "Viewer Options", NULL
, Icon_NOICON
,
1505 &encoding_item
, &word_wrap_item
, &line_mode_item
, &view_mode_item
,
1506 #ifdef HAVE_LCD_BITMAP
1507 &scrollbar_item
, &page_mode_item
,
1509 &scroll_mode_item
, &autoscroll_speed_item
);
1511 static bool viewer_options_menu(void)
1514 result
= (rb
->do_menu(&option_menu
, NULL
, NULL
, false) == MENU_ATTACHED_USB
);
1516 #ifdef HAVE_LCD_BITMAP
1517 /* Show-scrollbar mode for current view-width mode */
1518 init_need_scrollbar();
1523 static void viewer_menu(void)
1526 MENUITEM_STRINGLIST(menu
, "Viewer Menu", NULL
,
1527 "Return", "Viewer Options",
1528 "Show Playback Menu", "Quit");
1530 result
= rb
->do_menu(&menu
, NULL
, NULL
, false);
1533 case 0: /* return */
1535 case 1: /* change settings */
1536 done
= viewer_options_menu();
1538 case 2: /* playback control */
1539 playback_control(NULL
);
1549 enum plugin_status
plugin_start(const void* file
)
1552 int lastbutton
= BUTTON_NONE
;
1553 bool autoscroll
= false;
1556 old_tick
= *rb
->current_tick
;
1558 /* get the plugin buffer */
1559 buffer
= rb
->plugin_get_buffer((size_t *)&buffer_size
);
1562 return PLUGIN_ERROR
;
1567 rb
->splash(HZ
, "Error opening file.");
1568 return PLUGIN_ERROR
;
1571 viewer_load_settings(); /* load the preferences and bookmark */
1574 rb
->lcd_set_backdrop(NULL
);
1583 if(old_tick
<= *rb
->current_tick
- (110-prefs
.autoscroll_speed
*10))
1585 viewer_scroll_down();
1587 old_tick
= *rb
->current_tick
;
1591 button
= rb
->button_get_w_tmo(HZ
/10);
1597 case VIEWER_AUTOSCROLL
:
1598 #ifdef VIEWER_AUTOSCROLL_PRE
1599 if (lastbutton
!= VIEWER_AUTOSCROLL_PRE
)
1602 autoscroll
= !autoscroll
;
1605 case VIEWER_PAGE_UP
:
1606 case VIEWER_PAGE_UP
| BUTTON_REPEAT
:
1607 if (prefs
.scroll_mode
== PAGE
)
1610 #ifdef HAVE_LCD_BITMAP
1611 for (i
= prefs
.page_mode
==OVERLAP
? 1:0; i
< display_lines
; i
++)
1613 for (i
= 0; i
< display_lines
; i
++)
1619 old_tick
= *rb
->current_tick
;
1623 case VIEWER_PAGE_DOWN
:
1624 case VIEWER_PAGE_DOWN
| BUTTON_REPEAT
:
1625 if (prefs
.scroll_mode
== PAGE
)
1628 if (next_screen_ptr
!= NULL
)
1629 screen_top_ptr
= next_screen_to_draw_ptr
;
1632 viewer_scroll_down();
1633 old_tick
= *rb
->current_tick
;
1637 case VIEWER_SCREEN_LEFT
:
1638 case VIEWER_SCREEN_LEFT
| BUTTON_REPEAT
:
1639 if (prefs
.view_mode
== WIDE
) {
1641 col
-= draw_columns
;
1642 col
= col_limit(col
);
1644 else { /* prefs.view_mode == NARROW */
1652 case VIEWER_SCREEN_RIGHT
:
1653 case VIEWER_SCREEN_RIGHT
| BUTTON_REPEAT
:
1654 if (prefs
.view_mode
== WIDE
) {
1656 col
+= draw_columns
;
1657 col
= col_limit(col
);
1659 else { /* prefs.view_mode == NARROW */
1660 /* Bottom of file */
1667 #ifdef VIEWER_LINE_UP
1668 case VIEWER_LINE_UP
:
1669 case VIEWER_LINE_UP
| BUTTON_REPEAT
:
1670 /* Scroll up one line */
1672 old_tick
= *rb
->current_tick
;
1676 case VIEWER_LINE_DOWN
:
1677 case VIEWER_LINE_DOWN
| BUTTON_REPEAT
:
1678 /* Scroll down one line */
1679 if (next_screen_ptr
!= NULL
)
1680 screen_top_ptr
= next_line_ptr
;
1681 old_tick
= *rb
->current_tick
;
1685 #ifdef VIEWER_COLUMN_LEFT
1686 case VIEWER_COLUMN_LEFT
:
1687 case VIEWER_COLUMN_LEFT
| BUTTON_REPEAT
:
1688 if (prefs
.view_mode
== WIDE
) {
1689 /* Scroll left one column */
1690 col
-= glyph_width('o');
1691 col
= col_limit(col
);
1696 case VIEWER_COLUMN_RIGHT
:
1697 case VIEWER_COLUMN_RIGHT
| BUTTON_REPEAT
:
1698 if (prefs
.view_mode
== WIDE
) {
1699 /* Scroll right one column */
1700 col
+= glyph_width('o');
1701 col
= col_limit(col
);
1707 #ifdef VIEWER_RC_QUIT
1708 case VIEWER_RC_QUIT
:
1716 if (rb
->default_event_handler_ex(button
, viewer_exit
, NULL
)
1717 == SYS_USB_CONNECTED
)
1718 return PLUGIN_USB_CONNECTED
;
1721 if (button
!= BUTTON_NONE
)
1723 lastbutton
= button
;