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 /* global settings file
28 * binary file, so dont use .cfg
33 * --------------------------------
50 #define GLOBAL_SETTINGS_FILE VIEWERS_DIR "/viewer.dat"
53 #define GLOBAL_SETTINGS_TMP_FILE VIEWERS_DIR "/viewer_file.tmp"
55 #define GLOBAL_SETTINGS_HEADER "\x54\x56\x47\x53\x31" /* header="TVGS" version=1 */
56 #define GLOBAL_SETTINGS_H_SIZE 5
58 /* preferences and bookmarks at each file
59 * binary file, so dont use .cfg
64 * --------------------------------
98 #define SETTINGS_FILE VIEWERS_DIR "/viewer_file.dat"
101 #define SETTINGS_TMP_FILE VIEWERS_DIR "/viewer_file.tmp"
103 #define SETTINGS_HEADER "\x54\x56\x53\x32" /* header="TVS" version=2 */
104 #define SETTINGS_H_SIZE 4
106 #define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */
107 #define NARROW_MAX_COLUMNS 64 /* Max displayable string len [narrow] (over-estimate) */
108 #define WIDE_MAX_COLUMNS 128 /* Max displayable string len [wide] (over-estimate) */
109 #define MAX_WIDTH 910 /* Max line length in WIDE mode */
110 #define READ_PREV_ZONE (block_size*9/10) /* Arbitrary number less than SMALL_BLOCK_SIZE */
111 #define SMALL_BLOCK_SIZE block_size /* Smallest file chunk we will read */
112 #define LARGE_BLOCK_SIZE (block_size << 1) /* Preferable size of file chunk to read */
113 #define TOP_SECTOR buffer
114 #define MID_SECTOR (buffer + SMALL_BLOCK_SIZE)
115 #define BOTTOM_SECTOR (buffer + (SMALL_BLOCK_SIZE << 1))
116 #undef SCROLLBAR_WIDTH
117 #define SCROLLBAR_WIDTH rb->global_settings->scrollbar_width
118 #define MAX_PAGE 9999
120 #define BOOKMARK_SIZE 8
121 #define MAX_BOOKMARKS 10 /* user setting bookmarks + last read page */
123 #define BOOKMARK_LAST 1
124 #define BOOKMARK_USER 2
126 #ifndef HAVE_LCD_BITMAP
127 #define BOOKMARK_ICON "\xee\x84\x81\x00"
130 #define PREFERENCES_SIZE (11 + MAX_PATH)
132 /* Out-Of-Bounds test for any pointer to data in the buffer */
133 #define BUFFER_OOB(p) ((p) < buffer || (p) >= buffer_end)
135 /* Does the buffer contain the beginning of the file? */
136 #define BUFFER_BOF() (file_pos==0)
138 /* Does the buffer contain the end of the file? */
139 #define BUFFER_EOF() (file_size-file_pos <= buffer_size)
141 /* Formula for the endpoint address outside of buffer data */
142 #define BUFFER_END() \
143 ((BUFFER_EOF()) ? (file_size-file_pos+buffer) : (buffer+buffer_size))
145 /* Is the entire file being shown in one screen? */
146 #define ONE_SCREEN_FITS_ALL() \
147 (next_screen_ptr==NULL && screen_top_ptr==buffer && BUFFER_BOF())
149 /* Is a scrollbar called for on the current screen? */
150 #define NEED_SCROLLBAR() \
151 ((!(ONE_SCREEN_FITS_ALL())) && (prefs.scrollbar_mode==SB_ON))
153 /* variable button definitions */
156 #if CONFIG_KEYPAD == RECORDER_PAD
157 #define VIEWER_QUIT BUTTON_OFF
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_F1
163 #define VIEWER_AUTOSCROLL BUTTON_PLAY
164 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
165 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
166 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
167 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
168 #define VIEWER_BOOKMARK BUTTON_F2
170 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
171 #define VIEWER_QUIT BUTTON_OFF
172 #define VIEWER_PAGE_UP BUTTON_UP
173 #define VIEWER_PAGE_DOWN BUTTON_DOWN
174 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
175 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
176 #define VIEWER_MENU BUTTON_F1
177 #define VIEWER_AUTOSCROLL BUTTON_SELECT
178 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
179 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
180 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
181 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
182 #define VIEWER_BOOKMARK BUTTON_F2
185 #elif CONFIG_KEYPAD == ONDIO_PAD
186 #define VIEWER_QUIT BUTTON_OFF
187 #define VIEWER_PAGE_UP BUTTON_UP
188 #define VIEWER_PAGE_DOWN BUTTON_DOWN
189 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
190 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
191 #define VIEWER_MENU (BUTTON_MENU|BUTTON_REPEAT)
192 #define VIEWER_AUTOSCROLL_PRE BUTTON_MENU
193 #define VIEWER_AUTOSCROLL (BUTTON_MENU|BUTTON_REL)
194 #define VIEWER_BOOKMARK (BUTTON_MENU|BUTTON_OFF)
197 #elif CONFIG_KEYPAD == PLAYER_PAD
198 #define VIEWER_QUIT BUTTON_STOP
199 #define VIEWER_PAGE_UP BUTTON_LEFT
200 #define VIEWER_PAGE_DOWN BUTTON_RIGHT
201 #define VIEWER_SCREEN_LEFT (BUTTON_ON|BUTTON_LEFT)
202 #define VIEWER_SCREEN_RIGHT (BUTTON_ON|BUTTON_RIGHT)
203 #define VIEWER_MENU BUTTON_MENU
204 #define VIEWER_AUTOSCROLL BUTTON_PLAY
205 #define VIEWER_BOOKMARK BUTTON_ON
207 /* iRiver H1x0 && H3x0 keys */
208 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
209 (CONFIG_KEYPAD == IRIVER_H300_PAD)
210 #define VIEWER_QUIT BUTTON_OFF
211 #define VIEWER_PAGE_UP BUTTON_UP
212 #define VIEWER_PAGE_DOWN BUTTON_DOWN
213 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
214 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
215 #define VIEWER_MENU BUTTON_MODE
216 #define VIEWER_AUTOSCROLL BUTTON_SELECT
217 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
218 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
219 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
220 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
221 #define VIEWER_BOOKMARK (BUTTON_ON | BUTTON_SELECT)
223 #define VIEWER_RC_QUIT BUTTON_RC_STOP
226 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
227 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
228 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
229 #define VIEWER_QUIT_PRE BUTTON_SELECT
230 #define VIEWER_QUIT (BUTTON_SELECT | BUTTON_MENU)
231 #define VIEWER_PAGE_UP BUTTON_SCROLL_BACK
232 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_FWD
233 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
234 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
235 #define VIEWER_MENU BUTTON_MENU
236 #define VIEWER_AUTOSCROLL BUTTON_PLAY
237 #define VIEWER_BOOKMARK BUTTON_SELECT
240 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
241 #define VIEWER_QUIT BUTTON_PLAY
242 #define VIEWER_PAGE_UP BUTTON_UP
243 #define VIEWER_PAGE_DOWN BUTTON_DOWN
244 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
245 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
246 #define VIEWER_MENU BUTTON_MODE
247 #define VIEWER_AUTOSCROLL BUTTON_SELECT
248 #define VIEWER_BOOKMARK (BUTTON_LEFT|BUTTON_SELECT)
251 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
252 #define VIEWER_QUIT BUTTON_POWER
253 #define VIEWER_PAGE_UP BUTTON_UP
254 #define VIEWER_PAGE_DOWN BUTTON_DOWN
255 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
256 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
257 #define VIEWER_MENU BUTTON_SELECT
258 #define VIEWER_AUTOSCROLL BUTTON_PLAY
259 #define VIEWER_BOOKMARK BUTTON_REC
262 #elif CONFIG_KEYPAD == GIGABEAT_PAD
263 #define VIEWER_QUIT BUTTON_POWER
264 #define VIEWER_PAGE_UP BUTTON_UP
265 #define VIEWER_PAGE_DOWN BUTTON_DOWN
266 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
267 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
268 #define VIEWER_MENU BUTTON_MENU
269 #define VIEWER_AUTOSCROLL BUTTON_A
270 #define VIEWER_BOOKMARK BUTTON_SELECT
272 /* Sansa E200 keys */
273 #elif CONFIG_KEYPAD == SANSA_E200_PAD
274 #define VIEWER_QUIT BUTTON_POWER
275 #define VIEWER_PAGE_UP BUTTON_UP
276 #define VIEWER_PAGE_DOWN BUTTON_DOWN
277 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
278 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
279 #define VIEWER_MENU BUTTON_SELECT
280 #define VIEWER_AUTOSCROLL BUTTON_REC
281 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
282 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
283 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
285 /* Sansa Fuze keys */
286 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
287 #define VIEWER_QUIT (BUTTON_HOME|BUTTON_REPEAT)
288 #define VIEWER_PAGE_UP BUTTON_UP
289 #define VIEWER_PAGE_DOWN BUTTON_DOWN
290 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
291 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
292 #define VIEWER_MENU BUTTON_SELECT|BUTTON_REPEAT
293 #define VIEWER_AUTOSCROLL BUTTON_SELECT|BUTTON_DOWN
294 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
295 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
296 #define VIEWER_BOOKMARK BUTTON_SELECT
298 /* Sansa C200 keys */
299 #elif CONFIG_KEYPAD == SANSA_C200_PAD
300 #define VIEWER_QUIT BUTTON_POWER
301 #define VIEWER_PAGE_UP BUTTON_VOL_UP
302 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
303 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
304 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
305 #define VIEWER_MENU BUTTON_SELECT
306 #define VIEWER_AUTOSCROLL BUTTON_REC
307 #define VIEWER_LINE_UP BUTTON_UP
308 #define VIEWER_LINE_DOWN BUTTON_DOWN
309 #define VIEWER_BOOKMARK (BUTTON_DOWN | BUTTON_SELECT)
311 /* Sansa Clip keys */
312 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
313 #define VIEWER_QUIT BUTTON_POWER
314 #define VIEWER_PAGE_UP BUTTON_VOL_UP
315 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
316 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
317 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
318 #define VIEWER_MENU BUTTON_SELECT
319 #define VIEWER_AUTOSCROLL BUTTON_HOME
320 #define VIEWER_LINE_UP BUTTON_UP
321 #define VIEWER_LINE_DOWN BUTTON_DOWN
322 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
324 /* Sansa M200 keys */
325 #elif CONFIG_KEYPAD == SANSA_M200_PAD
326 #define VIEWER_QUIT BUTTON_POWER
327 #define VIEWER_PAGE_UP BUTTON_VOL_UP
328 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
329 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
330 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
331 #define VIEWER_MENU (BUTTON_SELECT | BUTTON_UP)
332 #define VIEWER_AUTOSCROLL (BUTTON_SELECT | BUTTON_REL)
333 #define VIEWER_LINE_UP BUTTON_UP
334 #define VIEWER_LINE_DOWN BUTTON_DOWN
335 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
337 /* iriver H10 keys */
338 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
339 #define VIEWER_QUIT BUTTON_POWER
340 #define VIEWER_PAGE_UP BUTTON_SCROLL_UP
341 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_DOWN
342 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
343 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
344 #define VIEWER_MENU BUTTON_REW
345 #define VIEWER_AUTOSCROLL BUTTON_PLAY
346 #define VIEWER_BOOKMARK BUTTON_FF
349 #elif CONFIG_KEYPAD == MROBE500_PAD
350 #define VIEWER_QUIT BUTTON_POWER
351 #define VIEWER_PAGE_UP BUTTON_RC_PLAY
352 #define VIEWER_PAGE_DOWN BUTTON_RC_DOWN
353 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
354 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
355 #define VIEWER_MENU BUTTON_RC_HEART
356 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
357 #define VIEWER_BOOKMARK BUTTON_CENTER
360 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
361 #define VIEWER_QUIT BUTTON_BACK
362 #define VIEWER_PAGE_UP BUTTON_PREV
363 #define VIEWER_PAGE_DOWN BUTTON_NEXT
364 #define VIEWER_SCREEN_LEFT (BUTTON_PLAY | BUTTON_LEFT)
365 #define VIEWER_SCREEN_RIGHT (BUTTON_PLAY | BUTTON_RIGHT)
366 #define VIEWER_MENU BUTTON_MENU
367 #define VIEWER_AUTOSCROLL_PRE BUTTON_PLAY
368 #define VIEWER_AUTOSCROLL (BUTTON_PLAY|BUTTON_REL)
369 #define VIEWER_LINE_UP BUTTON_UP
370 #define VIEWER_LINE_DOWN BUTTON_DOWN
371 #define VIEWER_COLUMN_LEFT BUTTON_LEFT
372 #define VIEWER_COLUMN_RIGHT BUTTON_RIGHT
373 #define VIEWER_BOOKMARK BUTTON_SELECT
376 #elif CONFIG_KEYPAD == MROBE100_PAD
377 #define VIEWER_QUIT BUTTON_POWER
378 #define VIEWER_PAGE_UP BUTTON_UP
379 #define VIEWER_PAGE_DOWN BUTTON_DOWN
380 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
381 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
382 #define VIEWER_MENU BUTTON_MENU
383 #define VIEWER_AUTOSCROLL BUTTON_DISPLAY
384 #define VIEWER_BOOKMARK BUTTON_SELECT
387 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
388 #define VIEWER_QUIT BUTTON_REC
389 #define VIEWER_PAGE_UP BUTTON_RC_VOL_UP
390 #define VIEWER_PAGE_DOWN BUTTON_RC_VOL_DOWN
391 #define VIEWER_SCREEN_LEFT BUTTON_RC_REW
392 #define VIEWER_SCREEN_RIGHT BUTTON_RC_FF
393 #define VIEWER_MENU BUTTON_RC_MENU
394 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
395 #define VIEWER_RC_QUIT BUTTON_RC_REC
396 #define VIEWER_BOOKMARK BUTTON_RC_PLAY
399 #elif CONFIG_KEYPAD == COWON_D2_PAD
400 #define VIEWER_QUIT BUTTON_POWER
401 #define VIEWER_MENU BUTTON_MENU
402 #define VIEWER_PAGE_UP BUTTON_MINUS
403 #define VIEWER_PAGE_DOWN BUTTON_PLUS
404 #define VIEWER_BOOKMARK (BUTTON_MENU|BUTTON_PLUS)
406 #elif CONFIG_KEYPAD == IAUDIO67_PAD
407 #define VIEWER_QUIT BUTTON_POWER
408 #define VIEWER_PAGE_UP BUTTON_VOLUP
409 #define VIEWER_PAGE_DOWN BUTTON_VOLDOWN
410 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
411 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
412 #define VIEWER_MENU BUTTON_MENU
413 #define VIEWER_AUTOSCROLL BUTTON_PLAY
414 #define VIEWER_RC_QUIT BUTTON_STOP
415 #define VIEWER_BOOKMARK (BUTTON_LEFT|BUTTON_PLAY)
417 /* Creative Zen Vision:M keys */
418 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
419 #define VIEWER_QUIT BUTTON_BACK
420 #define VIEWER_PAGE_UP BUTTON_UP
421 #define VIEWER_PAGE_DOWN BUTTON_DOWN
422 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
423 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
424 #define VIEWER_MENU BUTTON_MENU
425 #define VIEWER_AUTOSCROLL BUTTON_SELECT
426 #define VIEWER_BOOKMARK BUTTON_PLAY
428 /* Philips HDD1630 keys */
429 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
430 #define VIEWER_QUIT BUTTON_POWER
431 #define VIEWER_PAGE_UP BUTTON_UP
432 #define VIEWER_PAGE_DOWN BUTTON_DOWN
433 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
434 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
435 #define VIEWER_MENU BUTTON_MENU
436 #define VIEWER_AUTOSCROLL BUTTON_VIEW
437 #define VIEWER_BOOKMARK BUTTON_SELECT
439 /* Philips SA9200 keys */
440 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
441 #define VIEWER_QUIT BUTTON_POWER
442 #define VIEWER_PAGE_UP BUTTON_UP
443 #define VIEWER_PAGE_DOWN BUTTON_DOWN
444 #define VIEWER_SCREEN_LEFT BUTTON_PREV
445 #define VIEWER_SCREEN_RIGHT BUTTON_NEXT
446 #define VIEWER_MENU BUTTON_MENU
447 #define VIEWER_AUTOSCROLL BUTTON_PLAY
448 #define VIEWER_BOOKMARK BUTTON_RIGHT
450 /* Onda VX747 keys */
451 #elif CONFIG_KEYPAD == ONDAVX747_PAD
452 #define VIEWER_QUIT BUTTON_POWER
453 #define VIEWER_MENU BUTTON_MENU
454 #define VIEWER_BOOKMARK (BUTTON_RIGHT|BUTTON_POWER)
456 /* Onda VX777 keys */
457 #elif CONFIG_KEYPAD == ONDAVX777_PAD
458 #define VIEWER_QUIT BUTTON_POWER
459 #define VIEWER_BOOKMARK (BUTTON_RIGHT|BUTTON_POWER)
461 /* SAMSUNG YH-820 / YH-920 / YH-925 keys */
462 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
463 #define VIEWER_QUIT BUTTON_REC
464 #define VIEWER_PAGE_UP BUTTON_UP
465 #define VIEWER_PAGE_DOWN BUTTON_DOWN
466 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
467 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
468 #define VIEWER_MENU BUTTON_PLAY
469 #define VIEWER_AUTOSCROLL BUTTON_REW
470 #define VIEWER_BOOKMARK BUTTON_FFWD
472 /* Packard Bell Vibe 500 keys */
473 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
474 #define VIEWER_QUIT BUTTON_REC
475 #define VIEWER_PAGE_UP BUTTON_OK
476 #define VIEWER_PAGE_DOWN BUTTON_CANCEL
477 #define VIEWER_LINE_UP BUTTON_UP
478 #define VIEWER_LINE_DOWN BUTTON_DOWN
479 #define VIEWER_SCREEN_LEFT BUTTON_PREV
480 #define VIEWER_SCREEN_RIGHT BUTTON_NEXT
481 #define VIEWER_MENU BUTTON_MENU
482 #define VIEWER_AUTOSCROLL BUTTON_PLAY
483 #define VIEWER_BOOKMARK BUTTON_POWER
486 #error No keymap defined!
489 #ifdef HAVE_TOUCHSCREEN
491 #define VIEWER_QUIT2 BUTTON_TOPLEFT
493 #define VIEWER_QUIT BUTTON_TOPLEFT
495 #ifdef VIEWER_PAGE_UP
496 #define VIEWER_PAGE_UP2 BUTTON_TOPMIDDLE
498 #define VIEWER_PAGE_UP BUTTON_TOPMIDDLE
500 #ifdef VIEWER_PAGE_DOWN
501 #define VIEWER_PAGE_DOWN2 BUTTON_BOTTOMMIDDLE
503 #define VIEWER_PAGE_DOWN BUTTON_BOTTOMMIDDLE
505 #ifndef VIEWER_SCREEN_LEFT
506 #define VIEWER_SCREEN_LEFT BUTTON_MIDLEFT
508 #ifndef VIEWER_SCREEN_RIGHT
509 #define VIEWER_SCREEN_RIGHT BUTTON_MIDRIGHT
512 #define VIEWER_MENU2 BUTTON_TOPRIGHT
514 #define VIEWER_MENU BUTTON_TOPRIGHT
516 #ifndef VIEWER_AUTOSCROLL
517 #define VIEWER_AUTOSCROLL BUTTON_CENTER
521 /* stuff for the bookmarking */
522 struct bookmark_info
{
539 REFLOW
, /* won't be set on charcell LCD, must be last */
552 enum codepages encoding
;
584 int autoscroll_speed
;
586 unsigned char font
[MAX_PATH
];
590 VIEWER_FONT_MENU
= 0,
594 struct preferences prefs
;
595 struct preferences old_prefs
;
597 static unsigned char *buffer
;
598 static long buffer_size
;
599 static long block_size
= 0x1000;
600 static unsigned char line_break
[] = {0,0x20,9,0xB,0xC,'-'};
601 static int display_columns
; /* number of (pixel) columns on the display */
602 static int display_lines
; /* number of lines on the display */
603 static int draw_columns
; /* number of (pixel) columns available for text */
604 static int par_indent_spaces
; /* number of spaces to indent first paragraph */
606 static const char *file_name
;
607 static long file_size
;
608 static long start_position
; /* position in the file after the viewer is started */
609 static bool mac_text
;
610 static long file_pos
; /* Position of the top of the buffer in the file */
611 static long last_file_pos
;
612 static unsigned char *buffer_end
; /*Set to BUFFER_END() when file_pos changes*/
613 static int max_line_len
;
614 static int max_width
;
615 static int max_columns
;
616 static int cline
= 1;
617 static int cpage
= 1;
618 static int lpage
= 0;
619 static unsigned char *screen_top_ptr
;
620 static unsigned char *next_screen_ptr
;
621 static unsigned char *next_screen_to_draw_ptr
;
622 static unsigned char *next_line_ptr
;
623 static unsigned char *last_screen_top_ptr
= NULL
;
624 #ifdef HAVE_LCD_BITMAP
625 static struct font
*pf
;
626 static int header_height
= 0;
627 static int footer_height
= 0;
629 struct bookmark_info bookmarks
[MAX_BOOKMARKS
];
630 static int bookmark_count
;
633 #define BOM "\xef\xbb\xbf"
636 static bool is_bom
= false;
638 static int glyph_width(int ch
)
643 #ifdef HAVE_LCD_BITMAP
644 return rb
->font_get_width(pf
, ch
);
650 static unsigned char* get_ucs(const unsigned char* str
, unsigned short* ch
)
652 unsigned char utf8_tmp
[6];
655 if (prefs
.encoding
== UTF_8
)
656 return (unsigned char*)rb
->utf8decode(str
, ch
);
658 count
= BUFFER_OOB(str
+2)? 1:2;
659 rb
->iso_decode(str
, utf8_tmp
, prefs
.encoding
, count
);
660 rb
->utf8decode(utf8_tmp
, ch
);
662 #ifdef HAVE_LCD_BITMAP
663 if (prefs
.encoding
>= SJIS
&& *str
>= 0x80
664 && !(prefs
.encoding
== SJIS
&& *str
> 0xA0 && *str
< 0xE0))
665 return (unsigned char*)str
+2;
668 return (unsigned char*)str
+1;
671 static unsigned char *decode2utf8(const unsigned char *src
, unsigned char *dst
,
672 int skip_width
, int disp_width
)
675 const unsigned char *oldstr
;
676 const unsigned char *str
= src
;
677 unsigned char *utf8
= dst
;
683 str
= get_ucs(oldstr
, &ch
);
684 width
+= glyph_width(ch
);
685 if (width
> skip_width
)
694 str
= get_ucs(str
, &ch
);
695 width
+= glyph_width(ch
);
696 if (width
> disp_width
)
699 utf8
= rb
->utf8encode(ch
, utf8
);
705 static void calc_max_width(void)
707 if (prefs
.view_mode
== NARROW
)
709 max_columns
= NARROW_MAX_COLUMNS
;
710 max_width
= draw_columns
;
714 max_columns
= WIDE_MAX_COLUMNS
;
715 max_width
= 2 * draw_columns
;
722 #define ADVANCE_COUNTERS(c) { width += glyph_width(c); k++; }
723 #define LINE_IS_FULL ((k>=max_columns-1) ||( width >= max_width))
724 #define LINE_IS_NOT_FULL ((k<max_columns-1) &&( width < max_width))
725 static unsigned char* crop_at_width(const unsigned char* p
)
729 const unsigned char *oldp
= p
;
733 while (LINE_IS_NOT_FULL
) {
738 ADVANCE_COUNTERS(ch
);
741 return (unsigned char*)oldp
;
744 static unsigned char* find_first_feed(const unsigned char* p
, int size
)
748 for (i
=0; i
< size
; i
++)
750 return (unsigned char*) p
+i
;
755 static unsigned char* find_last_feed(const unsigned char* p
, int size
)
759 for (i
=size
-1; i
>=0; i
--)
761 return (unsigned char*) p
+i
;
766 static unsigned char* find_last_space(const unsigned char* p
, int size
)
770 k
= (prefs
.line_mode
==JOIN
) || (prefs
.line_mode
==REFLOW
) ? 0:1;
772 if (!BUFFER_OOB(&p
[size
]))
773 for (j
=k
; j
< ((int) sizeof(line_break
)) - 1; j
++)
774 if (p
[size
] == line_break
[j
])
775 return (unsigned char*) p
+size
;
777 for (i
=size
-1; i
>=0; i
--)
778 for (j
=k
; j
< (int) sizeof(line_break
); j
++)
780 if (!((p
[i
] == '-') && (prefs
.word_mode
== WRAP
)))
781 if (p
[i
] == line_break
[j
])
782 return (unsigned char*) p
+i
;
788 static unsigned char* find_next_line(const unsigned char* cur_line
, bool *is_short
)
790 const unsigned char *next_line
= NULL
;
791 int size
, i
, j
, k
, width
, search_len
, spaces
, newlines
;
795 if (is_short
!= NULL
)
798 if BUFFER_OOB(cur_line
)
801 if (prefs
.view_mode
== WIDE
) {
802 search_len
= MAX_WIDTH
;
804 else { /* prefs.view_mode == NARROW */
805 search_len
= crop_at_width(cur_line
) - cur_line
;
808 size
= BUFFER_OOB(cur_line
+search_len
) ? buffer_end
-cur_line
: search_len
;
810 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
)) {
811 /* Need to scan ahead and possibly increase search_len and size,
812 or possibly set next_line at second hard return in a row. */
815 for (j
=k
=width
=spaces
=newlines
=0; ; j
++) {
816 if (BUFFER_OOB(cur_line
+j
))
819 size
= search_len
= j
;
826 if (prefs
.line_mode
== REFLOW
) {
829 next_line
= cur_line
+ size
;
830 return (unsigned char*) next_line
;
832 if (j
==0) /* i=1 is intentional */
833 for (i
=0; i
<par_indent_spaces
; i
++)
834 ADVANCE_COUNTERS(' ');
836 if (!first_chars
) spaces
++;
842 next_line
= cur_line
+ size
- spaces
;
843 if (next_line
!= cur_line
)
844 return (unsigned char*) next_line
;
850 if (BUFFER_OOB(cur_line
+size
) || size
> 2*search_len
)
853 spaces
= first_chars
? 0:1;
857 if (prefs
.line_mode
==JOIN
|| newlines
>0) {
860 ADVANCE_COUNTERS(' ');
862 size
= search_len
= j
;
868 /* REFLOW, multiple spaces between words: count only
869 * one. If more are needed, they will be added
873 ADVANCE_COUNTERS(' ');
875 size
= search_len
= j
;
886 /* find first hard return */
887 next_line
= find_first_feed(cur_line
, size
);
890 if (next_line
== NULL
)
891 if (size
== search_len
) {
892 if (prefs
.word_mode
== WRAP
) /* Find last space */
893 next_line
= find_last_space(cur_line
, size
);
895 if (next_line
== NULL
)
896 next_line
= crop_at_width(cur_line
);
898 if (prefs
.word_mode
== WRAP
)
900 i
<WRAP_TRIM
&& isspace(next_line
[0]) && !BUFFER_OOB(next_line
);
905 if (prefs
.line_mode
== EXPAND
)
906 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
907 if (next_line
[0] == 0)
908 if (next_line
!= cur_line
)
909 return (unsigned char*) next_line
;
911 /* If next_line is pointing to a zero, increment it; i.e.,
912 leave the terminator at the end of cur_line. If pointing
913 to a hyphen, increment only if there is room to display
914 the hyphen on current line (won't apply in WIDE mode,
915 since it's guarenteed there won't be room). */
916 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
917 if (next_line
[0] == 0)/* ||
918 (next_line[0] == '-' && next_line-cur_line < draw_columns)) */
921 if (BUFFER_OOB(next_line
))
923 if (BUFFER_EOF() && next_line
!= cur_line
)
924 return (unsigned char*) next_line
;
931 return (unsigned char*) next_line
;
934 static unsigned char* find_prev_line(const unsigned char* cur_line
)
936 const unsigned char *prev_line
= NULL
;
937 const unsigned char *p
;
939 if BUFFER_OOB(cur_line
)
942 /* To wrap consistently at the same places, we must
943 start with a known hard return, then work downwards.
944 We can either search backwards for a hard return,
945 or simply start wrapping downwards from top of buffer.
946 If current line is not near top of buffer, this is
947 a file with long lines (paragraphs). We would need to
948 read earlier sectors before we could decide how to
949 properly wrap the lines above the current line, but
950 it probably is not worth the disk access. Instead,
951 start with top of buffer and wrap down from there.
952 This may result in some lines wrapping at different
953 points from where they wrap when scrolling down.
954 If buffer is at top of file, start at top of buffer. */
956 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
))
957 prev_line
= p
= NULL
;
959 prev_line
= p
= find_last_feed(buffer
, cur_line
-buffer
-1);
960 /* Null means no line feeds in buffer above current line. */
962 if (prev_line
== NULL
)
963 if (BUFFER_BOF() || cur_line
- buffer
> READ_PREV_ZONE
)
964 prev_line
= p
= buffer
;
965 /* (else return NULL and read previous block) */
967 /* Wrap downwards until too far, then use the one before. */
968 while (p
!= NULL
&& p
< cur_line
) {
970 p
= find_next_line(prev_line
, NULL
);
973 if (BUFFER_OOB(prev_line
))
976 return (unsigned char*) prev_line
;
979 static void check_bom(void)
981 unsigned char bom
[BOM_SIZE
];
982 off_t orig
= rb
->lseek(fd
, 0, SEEK_CUR
);
986 rb
->lseek(fd
, 0, SEEK_SET
);
988 if (rb
->read(fd
, bom
, BOM_SIZE
) == BOM_SIZE
)
989 is_bom
= !memcmp(bom
, BOM
, BOM_SIZE
);
991 rb
->lseek(fd
, orig
, SEEK_SET
);
994 static void fill_buffer(long pos
, unsigned char* buf
, unsigned size
)
996 /* Read from file and preprocess the data */
997 /* To minimize disk access, always read on sector boundaries */
999 bool found_CR
= false;
1000 off_t offset
= rb
->lseek(fd
, pos
, SEEK_SET
);
1002 if (offset
== 0 && prefs
.encoding
== UTF_8
&& is_bom
)
1003 rb
->lseek(fd
, BOM_SIZE
, SEEK_SET
);
1005 numread
= rb
->read(fd
, buf
, size
);
1007 rb
->button_clear_queue(); /* clear button queue */
1009 for(i
= 0; i
< numread
; i
++) {
1026 case 0: /* No break between case 0 and default, intentionally */
1039 static int viewer_find_bookmark(int page
, int line
)
1043 for (i
= 0; i
< bookmark_count
; i
++)
1045 if (bookmarks
[i
].page
== page
&& bookmarks
[i
].line
== line
)
1051 static int read_and_synch(int direction
)
1053 /* Read next (or prev) block, and reposition global pointers. */
1054 /* direction: 1 for down (i.e., further into file), -1 for up */
1055 int move_size
, move_vector
, offset
;
1056 unsigned char *fill_buf
;
1058 if (direction
== -1) /* up */ {
1059 move_size
= SMALL_BLOCK_SIZE
;
1061 fill_buf
= TOP_SECTOR
;
1062 rb
->memcpy(BOTTOM_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
1063 rb
->memcpy(MID_SECTOR
, TOP_SECTOR
, SMALL_BLOCK_SIZE
);
1066 if (prefs
.view_mode
== WIDE
) {
1067 /* WIDE mode needs more buffer so we have to read smaller blocks */
1068 move_size
= SMALL_BLOCK_SIZE
;
1069 offset
= LARGE_BLOCK_SIZE
;
1070 fill_buf
= BOTTOM_SECTOR
;
1071 rb
->memcpy(TOP_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
1072 rb
->memcpy(MID_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
1075 move_size
= LARGE_BLOCK_SIZE
;
1076 offset
= SMALL_BLOCK_SIZE
;
1077 fill_buf
= MID_SECTOR
;
1078 rb
->memcpy(TOP_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
1081 move_vector
= direction
* move_size
;
1082 screen_top_ptr
-= move_vector
;
1083 file_pos
+= move_vector
;
1084 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1085 fill_buffer(file_pos
+ offset
, fill_buf
, move_size
);
1089 static void get_next_line_position(unsigned char **line_begin
,
1090 unsigned char **line_end
,
1095 *line_begin
= *line_end
;
1096 *line_end
= find_next_line(*line_begin
, is_short
);
1098 if (*line_end
== NULL
&& !BUFFER_EOF())
1100 resynch_move
= read_and_synch(1); /* Read block & move ptrs */
1101 *line_begin
-= resynch_move
;
1102 if (next_line_ptr
> buffer
)
1103 next_line_ptr
-= resynch_move
;
1105 *line_end
= find_next_line(*line_begin
, is_short
);
1109 static void increment_current_line(void)
1111 if (cline
< display_lines
)
1113 else if (cpage
< MAX_PAGE
)
1120 static void decrement_current_line(void)
1127 cline
= display_lines
;
1131 static void viewer_scroll_up(void)
1135 p
= find_prev_line(screen_top_ptr
);
1136 if (p
== NULL
&& !BUFFER_BOF()) {
1138 p
= find_prev_line(screen_top_ptr
);
1143 decrement_current_line();
1146 static void viewer_scroll_down(bool autoscroll
)
1151 if (next_line_ptr
!= NULL
)
1152 screen_top_ptr
= next_line_ptr
;
1154 if (prefs
.scroll_mode
== LINE
|| autoscroll
)
1155 increment_current_line();
1158 static void viewer_scroll_to_top_line(void)
1162 for (line
= cline
; line
> 1; line
--)
1166 #ifdef HAVE_LCD_BITMAP
1167 static void viewer_scrollbar(void) {
1168 int items
, min_shown
, max_shown
, sb_begin_y
, sb_height
;
1170 items
= (int) file_size
; /* (SH1 int is same as long) */
1171 min_shown
= (int) file_pos
+ (screen_top_ptr
- buffer
);
1173 if (next_screen_ptr
== NULL
)
1176 max_shown
= min_shown
+ (next_screen_ptr
- screen_top_ptr
);
1178 sb_begin_y
= header_height
;
1179 sb_height
= LCD_HEIGHT
- header_height
- footer_height
;
1181 rb
->gui_scrollbar_draw(rb
->screens
[SCREEN_MAIN
],0, sb_begin_y
,
1182 SCROLLBAR_WIDTH
-1, sb_height
,
1183 items
, min_shown
, max_shown
, VERTICAL
);
1187 #ifdef HAVE_LCD_BITMAP
1188 static void viewer_show_header(void)
1190 if (prefs
.header_mode
== HD_SBAR
|| prefs
.header_mode
== HD_BOTH
)
1191 rb
->gui_syncstatusbar_draw(rb
->statusbars
, true);
1193 if (prefs
.header_mode
== HD_PATH
|| prefs
.header_mode
== HD_BOTH
)
1194 rb
->lcd_putsxy(0, header_height
- pf
->height
, file_name
);
1197 static void viewer_show_footer(void)
1199 if (prefs
.footer_mode
== FT_SBAR
|| prefs
.footer_mode
== FT_BOTH
)
1200 rb
->gui_syncstatusbar_draw(rb
->statusbars
, true);
1202 if (prefs
.footer_mode
== FT_PAGE
|| prefs
.footer_mode
== FT_BOTH
)
1204 unsigned char buf
[12];
1207 rb
->snprintf(buf
, sizeof(buf
), "%d", cpage
);
1209 rb
->snprintf(buf
, sizeof(buf
), "%d - %d", cpage
, cpage
+1);
1211 rb
->lcd_putsxy(0, LCD_HEIGHT
- footer_height
, buf
);
1216 static void viewer_draw(int col
)
1218 int i
, j
, k
, line_len
, line_width
, spaces
, left_col
=0;
1219 int width
, extra_spaces
, indent_spaces
, spaces_per_word
;
1220 bool multiple_spacing
, line_is_short
;
1222 unsigned char *str
, *oldstr
;
1223 unsigned char *line_begin
;
1224 unsigned char *line_end
;
1226 unsigned char scratch_buffer
[max_columns
+ 1];
1227 unsigned char utf8_buffer
[max_columns
*4 + 1];
1228 unsigned char *endptr
;
1230 /* If col==-1 do all calculations but don't display */
1232 #ifdef HAVE_LCD_BITMAP
1233 left_col
= prefs
.need_scrollbar
? SCROLLBAR_WIDTH
:0;
1237 rb
->lcd_clear_display();
1240 line_begin
= line_end
= screen_top_ptr
;
1242 for (i
= 0; i
< display_lines
; i
++) {
1243 if (BUFFER_OOB(line_end
))
1246 break; /* Happens after display last line at BUFFER_EOF() */
1248 if (lpage
== 0 && cline
== 1)
1251 last_screen_top_ptr
= screen_top_ptr
;
1252 last_file_pos
= file_pos
;
1256 get_next_line_position(&line_begin
, &line_end
, &line_is_short
);
1257 if (line_end
== NULL
)
1259 if (BUFFER_OOB(line_begin
))
1261 line_end
= buffer_end
+ 1;
1264 line_len
= line_end
- line_begin
;
1266 /* calculate line_len */
1267 str
= oldstr
= line_begin
;
1269 while (str
< line_end
) {
1271 str
= crop_at_width(str
);
1274 line_width
= j
*draw_columns
;
1275 while (oldstr
< line_end
) {
1276 oldstr
= get_ucs(oldstr
, &ch
);
1277 line_width
+= glyph_width(ch
);
1280 if (prefs
.line_mode
== JOIN
) {
1281 if (line_begin
[0] == 0) {
1283 if (prefs
.word_mode
== CHOP
)
1288 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
1289 if (k
== max_columns
)
1299 scratch_buffer
[k
++] = ' ';
1304 scratch_buffer
[k
++] = ' ';
1305 if (k
== max_columns
- 1)
1308 scratch_buffer
[k
++] = c
;
1313 scratch_buffer
[k
] = 0;
1314 endptr
= decode2utf8(scratch_buffer
, utf8_buffer
, col
, draw_columns
);
1318 else if (prefs
.line_mode
== REFLOW
) {
1319 if (line_begin
[0] == 0) {
1321 if (prefs
.word_mode
== CHOP
)
1328 if (!line_is_short
) {
1329 multiple_spacing
= false;
1331 for (str
= line_begin
; str
< line_end
; ) {
1332 str
= get_ucs(str
, &ch
);
1336 if ((str
== line_begin
) && (prefs
.word_mode
==WRAP
))
1337 /* special case: indent the paragraph,
1338 * don't count spaces */
1339 indent_spaces
= par_indent_spaces
;
1340 else if (!multiple_spacing
)
1342 multiple_spacing
= true;
1345 multiple_spacing
= false;
1346 width
+= glyph_width(ch
);
1350 if (multiple_spacing
) spaces
--;
1353 /* total number of spaces to insert between words */
1354 extra_spaces
= (max_width
-width
)/glyph_width(' ')
1356 /* number of spaces between each word*/
1357 spaces_per_word
= extra_spaces
/ spaces
;
1358 /* number of words with n+1 spaces (to fill up) */
1359 extra_spaces
= extra_spaces
% spaces
;
1360 if (spaces_per_word
> 2) { /* too much spacing is awful */
1361 spaces_per_word
= 3;
1364 } else { /* this doesn't matter much... no spaces anyway */
1365 spaces_per_word
= extra_spaces
= 0;
1367 } else { /* end of a paragraph: don't fill line */
1368 spaces_per_word
= 1;
1372 multiple_spacing
= false;
1373 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
1374 if (k
== max_columns
)
1381 if (j
==0 && prefs
.word_mode
==WRAP
) { /* indent paragraph */
1382 for (j
=0; j
<par_indent_spaces
; j
++)
1383 scratch_buffer
[k
++] = ' ';
1386 else if (!multiple_spacing
) {
1387 for (width
= spaces
<extra_spaces
? -1:0; width
< spaces_per_word
; width
++)
1388 scratch_buffer
[k
++] = ' ';
1391 multiple_spacing
= true;
1394 scratch_buffer
[k
++] = c
;
1395 multiple_spacing
= false;
1400 scratch_buffer
[k
] = 0;
1401 endptr
= decode2utf8(scratch_buffer
, utf8_buffer
, col
, draw_columns
);
1405 else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */
1407 if (line_width
> col
) {
1408 str
= oldstr
= line_begin
;
1411 while( (width
<draw_columns
) && (oldstr
<line_end
) )
1413 oldstr
= get_ucs(oldstr
, &ch
);
1415 k
-= glyph_width(ch
);
1416 line_begin
= oldstr
;
1418 width
+= glyph_width(ch
);
1422 if(prefs
.view_mode
==WIDE
)
1423 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1424 prefs
.encoding
, oldstr
-line_begin
);
1426 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1427 prefs
.encoding
, line_end
-line_begin
);
1431 if (col
!= -1 && line_width
> col
)
1433 int dpage
= (cline
+i
<= display_lines
)?cpage
:cpage
+1;
1434 int dline
= cline
+i
- ((cline
+i
<= display_lines
)?0:display_lines
);
1435 bool bflag
= (viewer_find_bookmark(dpage
, dline
) >= 0);
1436 #ifdef HAVE_LCD_BITMAP
1437 int dy
= i
* pf
->height
+ header_height
;
1438 int dx
= (prefs
.alignment
== LEFT
) ? left_col
: LCD_WIDTH
- line_width
;
1441 #ifdef HAVE_LCD_BITMAP
1443 rb
->lcd_set_drawmode(DRMODE_BG
|DRMODE_FG
);
1444 rb
->lcd_fillrect(left_col
, dy
, LCD_WIDTH
, pf
->height
);
1445 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
1447 rb
->lcd_putsxy(dx
, dy
, utf8_buffer
);
1448 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1451 rb
->lcd_puts(left_col
, i
, BOOKMARK_ICON
);
1453 rb
->lcd_puts(left_col
+1, i
, utf8_buffer
);
1456 if (line_width
> max_line_len
)
1457 max_line_len
= line_width
;
1460 next_line_ptr
= line_end
;
1462 next_screen_ptr
= line_end
;
1463 if (BUFFER_OOB(next_screen_ptr
))
1464 next_screen_ptr
= NULL
;
1466 #ifdef HAVE_LCD_BITMAP
1467 next_screen_to_draw_ptr
= prefs
.page_mode
==OVERLAP
? line_begin
: next_screen_ptr
;
1469 if (prefs
.need_scrollbar
)
1472 next_screen_to_draw_ptr
= next_screen_ptr
;
1475 #ifdef HAVE_LCD_BITMAP
1477 viewer_show_header();
1480 viewer_show_footer();
1487 static void viewer_top(void)
1489 /* Read top of file into buffer
1490 and point screen pointer to top */
1493 rb
->splash(0, "Loading...");
1496 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1497 fill_buffer(0, buffer
, buffer_size
);
1500 screen_top_ptr
= buffer
;
1505 static void viewer_bottom(void)
1507 unsigned char *line_begin
;
1508 unsigned char *line_end
;
1510 rb
->splash(0, "Loading...");
1512 if (last_screen_top_ptr
)
1516 screen_top_ptr
= last_screen_top_ptr
;
1517 file_pos
= last_file_pos
;
1518 fill_buffer(file_pos
, buffer
, buffer_size
);
1519 buffer_end
= BUFFER_END();
1523 line_end
= screen_top_ptr
;
1525 while (!BUFFER_EOF() || !BUFFER_OOB(line_end
))
1527 get_next_line_position(&line_begin
, &line_end
, NULL
);
1528 if (line_end
== NULL
)
1531 increment_current_line();
1533 screen_top_ptr
= line_end
;
1537 last_screen_top_ptr
= screen_top_ptr
;
1538 last_file_pos
= file_pos
;
1539 buffer_end
= BUFFER_END();
1542 #ifdef HAVE_LCD_BITMAP
1543 static void init_need_scrollbar(void) {
1544 /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
1545 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
1547 prefs
.need_scrollbar
= NEED_SCROLLBAR();
1548 draw_columns
= prefs
.need_scrollbar
? display_columns
-SCROLLBAR_WIDTH
: display_columns
;
1549 par_indent_spaces
= draw_columns
/(5*glyph_width(' '));
1553 static void init_header_and_footer(void)
1557 if (rb
->global_settings
->statusbar
== STATUSBAR_TOP
)
1559 if (prefs
.header_mode
== HD_SBAR
|| prefs
.header_mode
== HD_BOTH
)
1560 header_height
= STATUSBAR_HEIGHT
;
1562 if (prefs
.footer_mode
== FT_SBAR
)
1563 prefs
.footer_mode
= FT_NONE
;
1564 else if (prefs
.footer_mode
== FT_BOTH
)
1565 prefs
.footer_mode
= FT_PAGE
;
1567 else if (rb
->global_settings
->statusbar
== STATUSBAR_BOTTOM
)
1569 if (prefs
.footer_mode
== FT_SBAR
|| prefs
.footer_mode
== FT_BOTH
)
1570 footer_height
= STATUSBAR_HEIGHT
;
1572 if (prefs
.header_mode
== HD_SBAR
)
1573 prefs
.header_mode
= HD_NONE
;
1574 else if (prefs
.header_mode
== HD_BOTH
)
1575 prefs
.header_mode
= HD_PATH
;
1577 else /* STATUSBAR_OFF || STATUSBAR_CUSTOM */
1579 if (prefs
.header_mode
== HD_SBAR
)
1580 prefs
.header_mode
= HD_NONE
;
1581 else if (prefs
.header_mode
== HD_BOTH
)
1582 prefs
.header_mode
= HD_PATH
;
1584 if (prefs
.footer_mode
== FT_SBAR
)
1585 prefs
.footer_mode
= FT_NONE
;
1586 else if (prefs
.footer_mode
== FT_BOTH
)
1587 prefs
.footer_mode
= FT_PAGE
;
1590 if (prefs
.header_mode
== HD_NONE
|| prefs
.header_mode
== HD_PATH
||
1591 prefs
.footer_mode
== FT_NONE
|| prefs
.footer_mode
== FT_PAGE
)
1592 rb
->gui_syncstatusbar_draw(rb
->statusbars
, false);
1594 if (prefs
.header_mode
== HD_PATH
|| prefs
.header_mode
== HD_BOTH
)
1595 header_height
+= pf
->height
;
1596 if (prefs
.footer_mode
== FT_PAGE
|| prefs
.footer_mode
== FT_BOTH
)
1597 footer_height
+= pf
->height
;
1599 display_lines
= (LCD_HEIGHT
- header_height
- footer_height
) / pf
->height
;
1603 last_screen_top_ptr
= NULL
;
1606 static void change_font(unsigned char *font
)
1608 unsigned char buf
[MAX_PATH
];
1610 if (font
== NULL
|| *font
== '\0')
1613 rb
->snprintf(buf
, MAX_PATH
, "%s/%s.fnt", FONT_DIR
, font
);
1614 if (rb
->font_load(NULL
, buf
) < 0)
1615 rb
->splash(HZ
/2, "font load failed.");
1619 static bool viewer_init(void)
1621 #ifdef HAVE_LCD_BITMAP
1622 /* initialize fonts */
1623 pf
= rb
->font_get(FONT_UI
);
1624 draw_columns
= display_columns
= LCD_WIDTH
;
1626 /* REAL fixed pitch :) all chars use up 1 cell */
1628 draw_columns
= display_columns
= 11;
1629 par_indent_spaces
= 2;
1632 fd
= rb
->open(file_name
, O_RDONLY
);
1636 /* Init mac_text value used in processing buffer */
1642 /* When a file is UTF-8 file with BOM, if prefs.encoding is UTF-8,
1643 * then file size decreases only BOM_SIZE.
1645 static void get_filesize(void)
1647 file_size
= rb
->filesize(fd
);
1648 if (file_size
== -1)
1651 if (prefs
.encoding
== UTF_8
&& is_bom
)
1652 file_size
-= BOM_SIZE
;
1655 static int bm_comp(const void *a
, const void *b
)
1657 struct bookmark_info
*pa
;
1658 struct bookmark_info
*pb
;
1660 pa
= (struct bookmark_info
*)a
;
1661 pb
= (struct bookmark_info
*)b
;
1663 if (pa
->page
!= pb
->page
)
1664 return pa
->page
- pb
->page
;
1666 return pa
->line
- pb
->line
;
1669 static void viewer_add_bookmark(void)
1671 if (bookmark_count
>= MAX_BOOKMARKS
-1)
1674 bookmarks
[bookmark_count
].file_position
1675 = file_pos
+ screen_top_ptr
- buffer
;
1676 bookmarks
[bookmark_count
].page
= cpage
;
1677 bookmarks
[bookmark_count
].line
= cline
;
1678 bookmarks
[bookmark_count
].flag
= BOOKMARK_USER
;
1682 static int viewer_add_last_read_bookmark(void)
1686 i
= viewer_find_bookmark(cpage
, cline
);
1688 bookmarks
[i
].flag
|= BOOKMARK_LAST
;
1691 viewer_add_bookmark();
1692 i
= bookmark_count
-1;
1693 bookmarks
[i
].flag
= BOOKMARK_LAST
;
1698 static void viewer_remove_bookmark(int i
)
1702 if (i
< 0 || i
>= bookmark_count
)
1705 for (j
= i
+1; j
< bookmark_count
; j
++)
1706 rb
->memcpy(&bookmarks
[j
-1], &bookmarks
[j
],
1707 sizeof(struct bookmark_info
));
1712 static void viewer_remove_last_read_bookmark(void)
1716 for (i
= 0; i
< bookmark_count
; i
++)
1718 if (bookmarks
[i
].flag
& BOOKMARK_LAST
)
1720 if (bookmarks
[i
].flag
== BOOKMARK_LAST
)
1722 for (j
= i
+1; j
< bookmark_count
; j
++)
1723 rb
->memcpy(&bookmarks
[j
-1], &bookmarks
[j
],
1724 sizeof(struct bookmark_info
));
1729 bookmarks
[i
].flag
= BOOKMARK_USER
;
1735 static int viewer_get_last_read_bookmark(void)
1739 for (i
= 0; i
< bookmark_count
; i
++)
1741 if (bookmarks
[i
].flag
& BOOKMARK_LAST
)
1747 static void viewer_select_bookmark(int initval
)
1756 struct opt_items items
[bookmark_count
];
1757 unsigned char names
[bookmark_count
][38];
1759 if (initval
>= 0 && initval
< bookmark_count
)
1761 ipage
= bookmarks
[initval
].page
;
1762 iline
= bookmarks
[initval
].line
;
1765 rb
->qsort(bookmarks
, bookmark_count
, sizeof(struct bookmark_info
),
1768 for (i
= 0; i
< bookmark_count
; i
++)
1770 rb
->snprintf(names
[i
], sizeof(names
[0]),
1771 #if CONFIG_KEYPAD != PLAYER_PAD
1772 "%sPage: %d Line: %d",
1776 (bookmarks
[i
].flag
&BOOKMARK_LAST
)? "*":" ",
1779 items
[i
].string
= names
[i
];
1780 items
[i
].voice_id
= -1;
1781 if (selected
< 0 && bookmarks
[i
].page
== ipage
&& bookmarks
[i
].line
== iline
)
1785 rb
->set_option("Select bookmark", &selected
, INT
, items
,
1786 sizeof(items
) / sizeof(items
[0]), NULL
);
1788 if (selected
< 0 || selected
>= bookmark_count
)
1790 if (initval
< 0 || (selected
= viewer_get_last_read_bookmark()) < 0)
1793 rb
->splash(HZ
, "Start the first page.");
1795 screen_top_ptr
= buffer
;
1798 buffer_end
= BUFFER_END();
1803 screen_pos
= bookmarks
[selected
].file_position
;
1804 screen_top
= screen_pos
% buffer_size
;
1805 file_pos
= screen_pos
- screen_top
;
1806 screen_top_ptr
= buffer
+ screen_top
;
1807 cpage
= bookmarks
[selected
].page
;
1808 cline
= bookmarks
[selected
].line
;
1809 buffer_end
= BUFFER_END();
1812 static void viewer_default_preferences(void)
1814 prefs
.word_mode
= WRAP
;
1815 prefs
.line_mode
= NORMAL
;
1816 prefs
.view_mode
= NARROW
;
1817 prefs
.alignment
= LEFT
;
1818 prefs
.scroll_mode
= PAGE
;
1819 prefs
.page_mode
= NO_OVERLAP
;
1820 prefs
.scrollbar_mode
= SB_OFF
;
1821 rb
->memset(prefs
.font
, 0, MAX_PATH
);
1822 #ifdef HAVE_LCD_BITMAP
1823 prefs
.header_mode
= HD_BOTH
;
1824 prefs
.footer_mode
= FT_BOTH
;
1825 rb
->snprintf(prefs
.font
, MAX_PATH
, "%s", rb
->global_settings
->font_file
);
1827 prefs
.header_mode
= HD_NONE
;
1828 prefs
.footer_mode
= FT_NONE
;
1830 prefs
.autoscroll_speed
= 1;
1831 /* Set codepage to system default */
1832 prefs
.encoding
= rb
->global_settings
->default_codepage
;
1835 static bool viewer_read_preferences(int pfd
)
1837 unsigned char buf
[PREFERENCES_SIZE
];
1838 unsigned char *p
= buf
;
1840 if (rb
->read(pfd
, buf
, sizeof(buf
)) != sizeof(buf
))
1843 prefs
.word_mode
= *p
++;
1844 prefs
.line_mode
= *p
++;
1845 prefs
.view_mode
= *p
++;
1846 prefs
.alignment
= *p
++;
1847 prefs
.encoding
= *p
++;
1848 prefs
.scrollbar_mode
= *p
++;
1849 prefs
.need_scrollbar
= *p
++;
1850 prefs
.page_mode
= *p
++;
1851 prefs
.header_mode
= *p
++;
1852 prefs
.footer_mode
= *p
++;
1853 prefs
.scroll_mode
= *p
++;
1854 prefs
.autoscroll_speed
= *p
++;
1855 rb
->memcpy(prefs
.font
, p
, MAX_PATH
);
1860 static bool viewer_write_preferences(int pfd
)
1862 unsigned char buf
[PREFERENCES_SIZE
];
1863 unsigned char *p
= buf
;
1865 *p
++ = prefs
.word_mode
;
1866 *p
++ = prefs
.line_mode
;
1867 *p
++ = prefs
.view_mode
;
1868 *p
++ = prefs
.alignment
;
1869 *p
++ = prefs
.encoding
;
1870 *p
++ = prefs
.scrollbar_mode
;
1871 *p
++ = prefs
.need_scrollbar
;
1872 *p
++ = prefs
.page_mode
;
1873 *p
++ = prefs
.header_mode
;
1874 *p
++ = prefs
.footer_mode
;
1875 *p
++ = prefs
.scroll_mode
;
1876 *p
++ = prefs
.autoscroll_speed
;
1877 rb
->memcpy(p
, prefs
.font
, MAX_PATH
);
1879 return (rb
->write(pfd
, buf
, sizeof(buf
)) == sizeof(buf
));
1882 static bool viewer_read_bookmark_info(int bfd
, struct bookmark_info
*b
)
1884 unsigned char buf
[BOOKMARK_SIZE
];
1886 if (rb
->read(bfd
, buf
, sizeof(buf
)) != sizeof(buf
))
1889 b
->file_position
= (buf
[0] << 24)|(buf
[1] << 16)|(buf
[2] << 8)|buf
[3];
1890 b
->page
= (buf
[4] << 8)|buf
[5];
1897 static bool viewer_read_bookmark_infos(int bfd
)
1902 if (rb
->read(bfd
, &c
, 1) != 1)
1909 if (bookmark_count
> MAX_BOOKMARKS
)
1910 bookmark_count
= MAX_BOOKMARKS
;
1912 for (i
= 0; i
< bookmark_count
; i
++)
1914 if (!viewer_read_bookmark_info(bfd
, &bookmarks
[i
]))
1923 static bool viewer_write_bookmark_info(int bfd
, struct bookmark_info
*b
)
1925 unsigned char buf
[BOOKMARK_SIZE
];
1926 unsigned char *p
= buf
;
1929 ul
= b
->file_position
;
1942 return (rb
->write(bfd
, buf
, sizeof(buf
)) == sizeof(buf
));
1945 static bool viewer_write_bookmark_infos(int bfd
)
1947 unsigned char c
= bookmark_count
;
1950 if (rb
->write(bfd
, &c
, 1) != 1)
1953 for (i
= 0; i
< bookmark_count
; i
++)
1955 if (!viewer_write_bookmark_info(bfd
, &bookmarks
[i
]))
1962 static bool viewer_load_global_settings(void)
1964 unsigned buf
[GLOBAL_SETTINGS_H_SIZE
];
1965 int sfd
= rb
->open(GLOBAL_SETTINGS_FILE
, O_RDONLY
);
1970 if ((rb
->read(sfd
, buf
, GLOBAL_SETTINGS_H_SIZE
) != GLOBAL_SETTINGS_H_SIZE
) ||
1971 rb
->memcmp(buf
, GLOBAL_SETTINGS_HEADER
, GLOBAL_SETTINGS_H_SIZE
) ||
1972 !viewer_read_preferences(sfd
))
1981 static bool viewer_save_global_settings(void)
1983 int sfd
= rb
->open(GLOBAL_SETTINGS_TMP_FILE
, O_WRONLY
|O_CREAT
|O_TRUNC
);
1988 if (rb
->write(sfd
, &GLOBAL_SETTINGS_HEADER
, GLOBAL_SETTINGS_H_SIZE
)
1989 != GLOBAL_SETTINGS_H_SIZE
||
1990 !viewer_write_preferences(sfd
))
1993 rb
->remove(GLOBAL_SETTINGS_TMP_FILE
);
1997 rb
->remove(GLOBAL_SETTINGS_FILE
);
1998 rb
->rename(GLOBAL_SETTINGS_TMP_FILE
, GLOBAL_SETTINGS_FILE
);
2002 static void viewer_load_settings(void)
2004 unsigned char buf
[MAX_PATH
+2];
2005 unsigned int fcount
;
2011 sfd
= rb
->open(SETTINGS_FILE
, O_RDONLY
);
2015 if ((rb
->read(sfd
, buf
, SETTINGS_H_SIZE
+2) != SETTINGS_H_SIZE
+2) ||
2016 rb
->memcmp(buf
, SETTINGS_HEADER
, SETTINGS_H_SIZE
))
2018 /* illegal setting file */
2021 if (rb
->file_exists(SETTINGS_FILE
))
2022 rb
->remove(SETTINGS_FILE
);
2027 fcount
= (buf
[SETTINGS_H_SIZE
] << 8) | buf
[SETTINGS_H_SIZE
+1];
2028 for (i
= 0; i
< fcount
; i
++)
2030 if (rb
->read(sfd
, buf
, MAX_PATH
+2) != MAX_PATH
+2)
2033 size
= (buf
[MAX_PATH
] << 8) | buf
[MAX_PATH
+1];
2034 if (rb
->strcmp(buf
, file_name
))
2036 if (rb
->lseek(sfd
, size
, SEEK_CUR
) < 0)
2040 if (!viewer_read_preferences(sfd
))
2043 res
= viewer_read_bookmark_infos(sfd
);
2052 /* load global settings */
2053 if (!viewer_load_global_settings())
2054 viewer_default_preferences();
2057 screen_top_ptr
= buffer
;
2063 rb
->memcpy(&old_prefs
, &prefs
, sizeof(struct preferences
));
2066 if (bookmark_count
> 1)
2067 viewer_select_bookmark(-1);
2068 else if (bookmark_count
== 1)
2073 screen_pos
= bookmarks
[0].file_position
;
2074 screen_top
= screen_pos
% buffer_size
;
2075 file_pos
= screen_pos
- screen_top
;
2076 screen_top_ptr
= buffer
+ screen_top
;
2077 cpage
= bookmarks
[0].page
;
2078 cline
= bookmarks
[0].line
;
2081 viewer_remove_last_read_bookmark();
2086 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
2088 if (BUFFER_OOB(screen_top_ptr
))
2089 screen_top_ptr
= buffer
;
2091 fill_buffer(file_pos
, buffer
, buffer_size
);
2092 if (prefs
.scroll_mode
== PAGE
&& cline
> 1)
2093 viewer_scroll_to_top_line();
2095 /* remember the current position */
2096 start_position
= file_pos
+ screen_top_ptr
- buffer
;
2098 #ifdef HAVE_LCD_BITMAP
2099 if (rb
->strcmp(prefs
.font
, rb
->global_settings
->font_file
))
2100 change_font(prefs
.font
);
2102 init_need_scrollbar();
2103 init_header_and_footer();
2107 static bool copy_bookmark_file(int sfd
, int dfd
, off_t start
, off_t size
)
2111 if (rb
->lseek(sfd
, start
, SEEK_SET
) < 0)
2116 if (size
> buffer_size
)
2117 rsize
= buffer_size
;
2122 if (rb
->read(sfd
, buffer
, rsize
) != rsize
||
2123 rb
->write(dfd
, buffer
, rsize
) != rsize
)
2129 static bool viewer_save_settings(void)
2131 unsigned char buf
[MAX_PATH
+2];
2132 unsigned int fcount
= 0;
2137 off_t first_copy_size
= 0;
2138 off_t second_copy_start_pos
= 0;
2141 /* add reading page to bookmarks */
2142 idx
= viewer_find_bookmark(cpage
, cline
);
2144 bookmarks
[idx
].flag
|= BOOKMARK_LAST
;
2147 viewer_add_bookmark();
2148 bookmarks
[bookmark_count
-1].flag
= BOOKMARK_LAST
;
2151 tfd
= rb
->open(SETTINGS_TMP_FILE
, O_WRONLY
|O_CREAT
|O_TRUNC
);
2155 ofd
= rb
->open(SETTINGS_FILE
, O_RDWR
);
2158 if ((rb
->read(ofd
, buf
, SETTINGS_H_SIZE
+2) != SETTINGS_H_SIZE
+2) ||
2159 rb
->memcmp(buf
, SETTINGS_HEADER
, SETTINGS_H_SIZE
))
2164 fcount
= (buf
[SETTINGS_H_SIZE
] << 8) | buf
[SETTINGS_H_SIZE
+1];
2166 for (i
= 0; i
< fcount
; i
++)
2168 if (rb
->read(ofd
, buf
, MAX_PATH
+2) != MAX_PATH
+2)
2173 size
= (buf
[MAX_PATH
] << 8) | buf
[MAX_PATH
+1];
2174 if (rb
->strcmp(buf
, file_name
))
2176 if (rb
->lseek(ofd
, size
, SEEK_CUR
) < 0)
2184 first_copy_size
= rb
->lseek(ofd
, 0, SEEK_CUR
);
2185 if (first_copy_size
< 0)
2190 second_copy_start_pos
= first_copy_size
+ size
;
2191 first_copy_size
-= MAX_PATH
+2;
2196 if (first_copy_size
== 0)
2197 first_copy_size
= rb
->filesize(ofd
);
2199 if (!copy_bookmark_file(ofd
, tfd
, 0, first_copy_size
))
2204 if (second_copy_start_pos
> 0)
2206 if (!copy_bookmark_file(ofd
, tfd
, second_copy_start_pos
,
2207 rb
->filesize(ofd
) - second_copy_start_pos
))
2217 rb
->memcpy(buf
, SETTINGS_HEADER
, SETTINGS_H_SIZE
);
2218 buf
[SETTINGS_H_SIZE
] = 0;
2219 buf
[SETTINGS_H_SIZE
+1] = 0;
2220 if (rb
->write(tfd
, buf
, SETTINGS_H_SIZE
+2) != SETTINGS_H_SIZE
+2)
2224 /* copy to current read file's bookmarks */
2225 rb
->memset(buf
, 0, MAX_PATH
);
2226 rb
->snprintf(buf
, MAX_PATH
, "%s", file_name
);
2228 size
= PREFERENCES_SIZE
+ bookmark_count
* BOOKMARK_SIZE
+ 1;
2229 buf
[MAX_PATH
] = size
>> 8;
2230 buf
[MAX_PATH
+1] = size
;
2232 if (rb
->write(tfd
, buf
, MAX_PATH
+2) != MAX_PATH
+2)
2235 if (!viewer_write_preferences(tfd
))
2238 if (!viewer_write_bookmark_infos(tfd
))
2241 if (rb
->lseek(tfd
, SETTINGS_H_SIZE
, SEEK_SET
) < 0)
2245 buf
[0] = fcount
>> 8;
2248 if (rb
->write(tfd
, buf
, 2) != 2)
2253 rb
->remove(SETTINGS_FILE
);
2254 rb
->rename(SETTINGS_TMP_FILE
, SETTINGS_FILE
);
2260 rb
->remove(SETTINGS_TMP_FILE
);
2264 static void viewer_exit(void *parameter
)
2268 /* save preference and bookmarks */
2269 if (!viewer_save_settings())
2270 rb
->splash(HZ
, "Can't save preference and bookmarks.");
2273 #ifdef HAVE_LCD_BITMAP
2274 if (rb
->strcmp(prefs
.font
, rb
->global_settings
->font_file
))
2275 change_font(rb
->global_settings
->font_file
);
2279 static void calc_page(void)
2282 unsigned char *line_begin
;
2283 unsigned char *line_end
;
2285 unsigned char *sstp
;
2287 rb
->splash(0, "Calculating page/line number...");
2289 /* add reading page to bookmarks */
2290 viewer_add_last_read_bookmark();
2292 rb
->qsort(bookmarks
, bookmark_count
, sizeof(struct bookmark_info
),
2298 screen_top_ptr
= buffer
;
2299 buffer_end
= BUFFER_END();
2301 fill_buffer(file_pos
, buffer
, buffer_size
);
2302 line_end
= line_begin
= buffer
;
2304 for (i
= 0; i
< bookmark_count
; i
++)
2306 sfp
= bookmarks
[i
].file_position
;
2309 while ((line_begin
> sstp
|| sstp
>= line_end
) ||
2310 (file_pos
> sfp
|| sfp
>= file_pos
+ BUFFER_END() - buffer
))
2312 get_next_line_position(&line_begin
, &line_end
, NULL
);
2313 if (line_end
== NULL
)
2316 next_line_ptr
= line_end
;
2318 if (sstp
== buffer
&&
2319 file_pos
<= sfp
&& sfp
< file_pos
+ BUFFER_END() - buffer
)
2320 sstp
= sfp
- file_pos
+ buffer
;
2322 increment_current_line();
2325 decrement_current_line();
2326 bookmarks
[i
].page
= cpage
;
2327 bookmarks
[i
].line
= cline
;
2328 bookmarks
[i
].file_position
= file_pos
+ (line_begin
- buffer
);
2329 increment_current_line();
2332 /* remove reading page's bookmark */
2333 for (i
= 0; i
< bookmark_count
; i
++)
2335 if (bookmarks
[i
].flag
& BOOKMARK_LAST
)
2340 screen_pos
= bookmarks
[i
].file_position
;
2341 screen_top
= screen_pos
% buffer_size
;
2342 file_pos
= screen_pos
- screen_top
;
2343 screen_top_ptr
= buffer
+ screen_top
;
2345 cpage
= bookmarks
[i
].page
;
2346 cline
= bookmarks
[i
].line
;
2347 bookmarks
[i
].flag
^= BOOKMARK_LAST
;
2348 buffer_end
= BUFFER_END();
2350 fill_buffer(file_pos
, buffer
, buffer_size
);
2352 if (bookmarks
[i
].flag
== 0)
2353 viewer_remove_bookmark(i
);
2355 if (prefs
.scroll_mode
== PAGE
&& cline
> 1)
2356 viewer_scroll_to_top_line();
2362 static int col_limit(int col
)
2367 if (col
>= max_width
)
2368 col
= max_width
- draw_columns
;
2373 /* settings helper functions */
2375 static bool encoding_setting(void)
2377 static struct opt_items names
[NUM_CODEPAGES
];
2380 enum codepages oldenc
= prefs
.encoding
;
2382 for (idx
= 0; idx
< NUM_CODEPAGES
; idx
++)
2384 names
[idx
].string
= rb
->get_codepage_name(idx
);
2385 names
[idx
].voice_id
= -1;
2388 res
= rb
->set_option("Encoding", &prefs
.encoding
, INT
, names
,
2389 sizeof(names
) / sizeof(names
[0]), NULL
);
2391 /* When prefs.encoding changes into UTF-8 or changes from UTF-8,
2392 * filesize (file_size) might change.
2393 * In addition, if prefs.encoding is UTF-8, then BOM does not read.
2395 if (oldenc
!= prefs
.encoding
&& (oldenc
== UTF_8
|| prefs
.encoding
== UTF_8
))
2399 fill_buffer(file_pos
, buffer
, buffer_size
);
2405 static bool word_wrap_setting(void)
2407 static const struct opt_items names
[] = {
2409 {"Off (Chop Words)", -1},
2412 return rb
->set_option("Word Wrap", &prefs
.word_mode
, INT
,
2416 static bool line_mode_setting(void)
2418 static const struct opt_items names
[] = {
2421 {"Expand Lines", -1},
2422 #ifdef HAVE_LCD_BITMAP
2423 {"Reflow Lines", -1},
2427 return rb
->set_option("Line Mode", &prefs
.line_mode
, INT
, names
,
2428 sizeof(names
) / sizeof(names
[0]), NULL
);
2431 static bool view_mode_setting(void)
2433 static const struct opt_items names
[] = {
2434 {"No (Narrow)", -1},
2438 ret
= rb
->set_option("Wide View", &prefs
.view_mode
, INT
,
2440 if (prefs
.view_mode
== NARROW
)
2446 static bool scroll_mode_setting(void)
2448 static const struct opt_items names
[] = {
2449 {"Scroll by Page", -1},
2450 {"Scroll by Line", -1},
2453 return rb
->set_option("Scroll Mode", &prefs
.scroll_mode
, INT
,
2457 #ifdef HAVE_LCD_BITMAP
2458 static bool page_mode_setting(void)
2460 static const struct opt_items names
[] = {
2465 return rb
->set_option("Overlap Pages", &prefs
.page_mode
, INT
,
2469 static bool scrollbar_setting(void)
2471 static const struct opt_items names
[] = {
2476 return rb
->set_option("Show Scrollbar", &prefs
.scrollbar_mode
, INT
,
2480 static bool header_setting(void)
2482 int len
= (rb
->global_settings
->statusbar
== STATUSBAR_TOP
)? 4 : 2;
2483 struct opt_items names
[len
];
2485 names
[0].string
= "None";
2486 names
[0].voice_id
= -1;
2487 names
[1].string
= "File path";
2488 names
[1].voice_id
= -1;
2490 if (rb
->global_settings
->statusbar
== STATUSBAR_TOP
)
2492 names
[2].string
= "Status bar";
2493 names
[2].voice_id
= -1;
2494 names
[3].string
= "Both";
2495 names
[3].voice_id
= -1;
2498 return rb
->set_option("Show Header", &prefs
.header_mode
, INT
,
2502 static bool footer_setting(void)
2504 int len
= (rb
->global_settings
->statusbar
== STATUSBAR_BOTTOM
)? 4 : 2;
2505 struct opt_items names
[len
];
2507 names
[0].string
= "None";
2508 names
[0].voice_id
= -1;
2509 names
[1].string
= "Page Num";
2510 names
[1].voice_id
= -1;
2512 if (rb
->global_settings
->statusbar
== STATUSBAR_BOTTOM
)
2514 names
[2].string
= "Status bar";
2515 names
[2].voice_id
= -1;
2516 names
[3].string
= "Both";
2517 names
[3].voice_id
= -1;
2520 return rb
->set_option("Show Footer", &prefs
.footer_mode
, INT
,
2524 static int font_comp(const void *a
, const void *b
)
2526 struct opt_items
*pa
;
2527 struct opt_items
*pb
;
2529 pa
= (struct opt_items
*)a
;
2530 pb
= (struct opt_items
*)b
;
2532 return rb
->strcmp(pa
->string
, pb
->string
);
2535 static bool font_setting(void)
2539 struct dirent
*entry
;
2547 dir
= rb
->opendir(FONT_DIR
);
2550 rb
->splash(HZ
/2, "font dir does not access.");
2556 entry
= rb
->readdir(dir
);
2561 len
= rb
->strlen(entry
->d_name
);
2562 if (len
< 4 || rb
->strcmp(entry
->d_name
+ len
-4, ".fnt"))
2569 struct opt_items names
[count
];
2570 unsigned char font_names
[size
];
2571 unsigned char *p
= font_names
;
2573 dir
= rb
->opendir(FONT_DIR
);
2576 rb
->splash(HZ
/2, "font dir does not access.");
2582 entry
= rb
->readdir(dir
);
2587 len
= rb
->strlen(entry
->d_name
);
2588 if (len
< 4 || rb
->strcmp(entry
->d_name
+ len
-4, ".fnt"))
2591 rb
->snprintf(p
, len
-3, "%s", entry
->d_name
);
2592 names
[i
].string
= p
;
2593 names
[i
].voice_id
= -1;
2601 rb
->qsort(names
, count
, sizeof(struct opt_items
), font_comp
);
2603 for (i
= 0; i
< count
; i
++)
2605 if (!rb
->strcmp(names
[i
].string
, prefs
.font
))
2611 old_font
= new_font
;
2613 res
= rb
->set_option("Select Font", &new_font
, INT
,
2614 names
, count
, NULL
);
2616 if (new_font
!= old_font
)
2618 rb
->memset(prefs
.font
, 0, MAX_PATH
);
2619 rb
->snprintf(prefs
.font
, MAX_PATH
, "%s", names
[new_font
].string
);
2620 change_font(prefs
.font
);
2626 static bool alignment_setting(void)
2628 static const struct opt_items names
[] = {
2633 return rb
->set_option("Alignment", &prefs
.alignment
, INT
,
2638 static bool autoscroll_speed_setting(void)
2640 return rb
->set_int("Auto-scroll Speed", "", UNIT_INT
,
2641 &prefs
.autoscroll_speed
, NULL
, 1, 1, 10, NULL
);
2644 MENUITEM_FUNCTION(encoding_item
, 0, "Encoding", encoding_setting
,
2645 NULL
, NULL
, Icon_NOICON
);
2646 MENUITEM_FUNCTION(word_wrap_item
, 0, "Word Wrap", word_wrap_setting
,
2647 NULL
, NULL
, Icon_NOICON
);
2648 MENUITEM_FUNCTION(line_mode_item
, 0, "Line Mode", line_mode_setting
,
2649 NULL
, NULL
, Icon_NOICON
);
2650 MENUITEM_FUNCTION(view_mode_item
, 0, "Wide View", view_mode_setting
,
2651 NULL
, NULL
, Icon_NOICON
);
2652 #ifdef HAVE_LCD_BITMAP
2653 MENUITEM_FUNCTION(alignment_item
, 0, "Alignment", alignment_setting
,
2654 NULL
, NULL
, Icon_NOICON
);
2655 MENUITEM_FUNCTION(scrollbar_item
, 0, "Show Scrollbar", scrollbar_setting
,
2656 NULL
, NULL
, Icon_NOICON
);
2657 MENUITEM_FUNCTION(page_mode_item
, 0, "Overlap Pages", page_mode_setting
,
2658 NULL
, NULL
, Icon_NOICON
);
2659 MENUITEM_FUNCTION(header_item
, 0, "Show Header", header_setting
,
2660 NULL
, NULL
, Icon_NOICON
);
2661 MENUITEM_FUNCTION(footer_item
, 0, "Show Footer", footer_setting
,
2662 NULL
, NULL
, Icon_NOICON
);
2663 MENUITEM_FUNCTION(font_item
, 0, "Font", font_setting
,
2664 NULL
, NULL
, Icon_NOICON
);
2666 MENUITEM_FUNCTION(scroll_mode_item
, 0, "Scroll Mode", scroll_mode_setting
,
2667 NULL
, NULL
, Icon_NOICON
);
2668 MENUITEM_FUNCTION(autoscroll_speed_item
, 0, "Auto-Scroll Speed",
2669 autoscroll_speed_setting
, NULL
, NULL
, Icon_NOICON
);
2670 MAKE_MENU(option_menu
, "Viewer Options", NULL
, Icon_NOICON
,
2671 &encoding_item
, &word_wrap_item
, &line_mode_item
, &view_mode_item
,
2672 #ifdef HAVE_LCD_BITMAP
2673 &alignment_item
, &scrollbar_item
, &page_mode_item
, &header_item
,
2674 &footer_item
, &font_item
,
2676 &scroll_mode_item
, &autoscroll_speed_item
);
2678 static bool viewer_options_menu(bool is_global
)
2681 struct preferences tmp_prefs
;
2683 rb
->memcpy(&tmp_prefs
, &prefs
, sizeof(struct preferences
));
2685 result
= (rb
->do_menu(&option_menu
, NULL
, NULL
, false) == MENU_ATTACHED_USB
);
2687 if (!is_global
&& rb
->memcmp(&tmp_prefs
, &prefs
, sizeof(struct preferences
)))
2689 /* Show-scrollbar mode for current view-width mode */
2690 #ifdef HAVE_LCD_BITMAP
2691 init_need_scrollbar();
2692 init_header_and_footer();
2699 static void viewer_menu(void)
2703 MENUITEM_STRINGLIST(menu
, "Viewer Menu", NULL
,
2704 "Return", "Viewer Options",
2705 "Show Playback Menu", "Select Bookmark",
2706 "Global Settings", "Quit");
2708 result
= rb
->do_menu(&menu
, NULL
, NULL
, false);
2711 case 0: /* return */
2713 case 1: /* change settings */
2714 done
= viewer_options_menu(false);
2716 case 2: /* playback control */
2717 playback_control(NULL
);
2719 case 3: /* select bookmark */
2720 viewer_select_bookmark(viewer_add_last_read_bookmark());
2721 viewer_remove_last_read_bookmark();
2722 fill_buffer(file_pos
, buffer
, buffer_size
);
2723 if (prefs
.scroll_mode
== PAGE
&& cline
> 1)
2724 viewer_scroll_to_top_line();
2726 case 4: /* change global settings */
2728 struct preferences orig_prefs
;
2730 rb
->memcpy(&orig_prefs
, &prefs
, sizeof(struct preferences
));
2731 if (!viewer_load_global_settings())
2732 viewer_default_preferences();
2733 done
= viewer_options_menu(true);
2734 viewer_save_global_settings();
2735 rb
->memcpy(&prefs
, &orig_prefs
, sizeof(struct preferences
));
2746 enum plugin_status
plugin_start(const void* file
)
2749 int lastbutton
= BUTTON_NONE
;
2750 bool autoscroll
= false;
2753 old_tick
= *rb
->current_tick
;
2755 /* get the plugin buffer */
2756 buffer
= rb
->plugin_get_buffer((size_t *)&buffer_size
);
2757 if (buffer_size
== 0)
2759 rb
->splash(HZ
, "buffer does not allocate !!");
2760 return PLUGIN_ERROR
;
2762 block_size
= buffer_size
/ 3;
2763 buffer_size
= 3 * block_size
;
2766 return PLUGIN_ERROR
;
2771 rb
->splash(HZ
, "Error opening file.");
2772 return PLUGIN_ERROR
;
2775 viewer_load_settings(); /* load the preferences and bookmark */
2778 rb
->lcd_set_backdrop(NULL
);
2787 if(old_tick
<= *rb
->current_tick
- (110-prefs
.autoscroll_speed
*10))
2789 viewer_scroll_down(true);
2791 old_tick
= *rb
->current_tick
;
2795 button
= rb
->button_get_w_tmo(HZ
/10);
2797 if (prefs
.view_mode
!= WIDE
) {
2798 /* when not in wide view mode, the SCREEN_LEFT and SCREEN_RIGHT
2799 buttons jump to the beginning and end of the file. To stop
2800 users doing this by accident, replace non-held occurrences
2801 with page up/down instead. */
2802 if (button
== VIEWER_SCREEN_LEFT
)
2803 button
= VIEWER_PAGE_UP
;
2804 else if (button
== VIEWER_SCREEN_RIGHT
)
2805 button
= VIEWER_PAGE_DOWN
;
2816 case VIEWER_AUTOSCROLL
:
2817 #ifdef VIEWER_AUTOSCROLL_PRE
2818 if (lastbutton
!= VIEWER_AUTOSCROLL_PRE
)
2821 autoscroll
= !autoscroll
;
2824 case VIEWER_PAGE_UP
:
2825 case VIEWER_PAGE_UP
| BUTTON_REPEAT
:
2826 #ifdef VIEWER_PAGE_UP2
2827 case VIEWER_PAGE_UP2
:
2828 case VIEWER_PAGE_UP2
| BUTTON_REPEAT
:
2830 if (prefs
.scroll_mode
== PAGE
)
2833 #ifdef HAVE_LCD_BITMAP
2834 for (i
= prefs
.page_mode
==OVERLAP
? 1:0; i
< display_lines
; i
++)
2836 for (i
= 0; i
< display_lines
; i
++)
2842 old_tick
= *rb
->current_tick
;
2846 case VIEWER_PAGE_DOWN
:
2847 case VIEWER_PAGE_DOWN
| BUTTON_REPEAT
:
2848 #ifdef VIEWER_PAGE_DOWN2
2849 case VIEWER_PAGE_DOWN2
:
2850 case VIEWER_PAGE_DOWN2
| BUTTON_REPEAT
:
2852 if (prefs
.scroll_mode
== PAGE
)
2855 if (next_screen_ptr
!= NULL
)
2857 screen_top_ptr
= next_screen_to_draw_ptr
;
2858 if (cpage
< MAX_PAGE
)
2863 viewer_scroll_down(autoscroll
);
2864 old_tick
= *rb
->current_tick
;
2868 case VIEWER_SCREEN_LEFT
:
2869 case VIEWER_SCREEN_LEFT
| BUTTON_REPEAT
:
2870 if (prefs
.view_mode
== WIDE
) {
2872 col
-= draw_columns
;
2873 col
= col_limit(col
);
2875 else { /* prefs.view_mode == NARROW */
2883 case VIEWER_SCREEN_RIGHT
:
2884 case VIEWER_SCREEN_RIGHT
| BUTTON_REPEAT
:
2885 if (prefs
.view_mode
== WIDE
) {
2887 col
+= draw_columns
;
2888 col
= col_limit(col
);
2890 else { /* prefs.view_mode == NARROW */
2891 /* Bottom of file */
2898 #ifdef VIEWER_LINE_UP
2899 case VIEWER_LINE_UP
:
2900 case VIEWER_LINE_UP
| BUTTON_REPEAT
:
2901 /* Scroll up one line */
2903 old_tick
= *rb
->current_tick
;
2907 case VIEWER_LINE_DOWN
:
2908 case VIEWER_LINE_DOWN
| BUTTON_REPEAT
:
2909 /* Scroll down one line */
2910 viewer_scroll_down(autoscroll
);
2911 increment_current_line();
2912 old_tick
= *rb
->current_tick
;
2916 #ifdef VIEWER_COLUMN_LEFT
2917 case VIEWER_COLUMN_LEFT
:
2918 case VIEWER_COLUMN_LEFT
| BUTTON_REPEAT
:
2919 if (prefs
.view_mode
== WIDE
) {
2920 /* Scroll left one column */
2921 col
-= glyph_width('o');
2922 col
= col_limit(col
);
2927 case VIEWER_COLUMN_RIGHT
:
2928 case VIEWER_COLUMN_RIGHT
| BUTTON_REPEAT
:
2929 if (prefs
.view_mode
== WIDE
) {
2930 /* Scroll right one column */
2931 col
+= glyph_width('o');
2932 col
= col_limit(col
);
2938 #ifdef VIEWER_RC_QUIT
2939 case VIEWER_RC_QUIT
:
2949 case VIEWER_BOOKMARK
:
2951 int idx
= viewer_find_bookmark(cpage
, cline
);
2955 if (bookmark_count
>= MAX_BOOKMARKS
-1)
2956 rb
->splash(HZ
/2, "No more add bookmark.");
2959 viewer_add_bookmark();
2960 rb
->splash(HZ
/2, "Bookmark add.");
2965 viewer_remove_bookmark(idx
);
2966 rb
->splash(HZ
/2, "Bookmark remove.");
2973 if (rb
->default_event_handler_ex(button
, viewer_exit
, NULL
)
2974 == SYS_USB_CONNECTED
)
2975 return PLUGIN_USB_CONNECTED
;
2978 if (button
!= BUTTON_NONE
)
2980 lastbutton
= button
;