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 * --------------------------------
49 #define GLOBAL_SETTINGS_FILE VIEWERS_DIR "/viewer.dat"
52 #define GLOBAL_SETTINGS_TMP_FILE VIEWERS_DIR "/viewer_file.tmp"
54 #define GLOBAL_SETTINGS_HEADER "\x54\x56\x47\x53\x31" /* header="TVGS" version=1 */
55 #define GLOBAL_SETTINGS_H_SIZE 5
57 /* preferences and bookmarks at each file
58 * binary file, so dont use .cfg
63 * --------------------------------
96 #define SETTINGS_FILE VIEWERS_DIR "/viewer_file.dat"
99 #define SETTINGS_TMP_FILE VIEWERS_DIR "/viewer_file.tmp"
101 #define SETTINGS_HEADER "\x54\x56\x53\x32" /* header="TVS" version=2 */
102 #define SETTINGS_H_SIZE 4
104 #define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */
105 #define NARROW_MAX_COLUMNS 64 /* Max displayable string len [narrow] (over-estimate) */
106 #define WIDE_MAX_COLUMNS 128 /* Max displayable string len [wide] (over-estimate) */
107 #define MAX_WIDTH 910 /* Max line length in WIDE mode */
108 #define READ_PREV_ZONE (block_size*9/10) /* Arbitrary number less than SMALL_BLOCK_SIZE */
109 #define SMALL_BLOCK_SIZE block_size /* Smallest file chunk we will read */
110 #define LARGE_BLOCK_SIZE (block_size << 1) /* Preferable size of file chunk to read */
111 #define TOP_SECTOR buffer
112 #define MID_SECTOR (buffer + SMALL_BLOCK_SIZE)
113 #define BOTTOM_SECTOR (buffer + (SMALL_BLOCK_SIZE << 1))
114 #undef SCROLLBAR_WIDTH
115 #define SCROLLBAR_WIDTH rb->global_settings->scrollbar_width
116 #define MAX_PAGE 9999
118 #define BOOKMARK_SIZE 8
119 #define MAX_BOOKMARKS 10 /* user setting bookmarks + last read page */
121 #define BOOKMARK_LAST 1
122 #define BOOKMARK_USER 2
124 #ifndef HAVE_LCD_BITMAP
125 #define BOOKMARK_ICON "\xee\x84\x81\x00"
128 #define PREFERENCES_SIZE (11 + MAX_PATH)
130 /* Out-Of-Bounds test for any pointer to data in the buffer */
131 #define BUFFER_OOB(p) ((p) < buffer || (p) >= buffer_end)
133 /* Does the buffer contain the beginning of the file? */
134 #define BUFFER_BOF() (file_pos==0)
136 /* Does the buffer contain the end of the file? */
137 #define BUFFER_EOF() (file_size-file_pos <= buffer_size)
139 /* Formula for the endpoint address outside of buffer data */
140 #define BUFFER_END() \
141 ((BUFFER_EOF()) ? (file_size-file_pos+buffer) : (buffer+buffer_size))
143 /* Is the entire file being shown in one screen? */
144 #define ONE_SCREEN_FITS_ALL() \
145 (next_screen_ptr==NULL && screen_top_ptr==buffer && BUFFER_BOF())
147 /* Is a scrollbar called for on the current screen? */
148 #define NEED_SCROLLBAR() \
149 ((!(ONE_SCREEN_FITS_ALL())) && (prefs.scrollbar_mode==SB_ON))
151 /* variable button definitions */
154 #if CONFIG_KEYPAD == RECORDER_PAD
155 #define VIEWER_QUIT BUTTON_OFF
156 #define VIEWER_PAGE_UP BUTTON_UP
157 #define VIEWER_PAGE_DOWN BUTTON_DOWN
158 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
159 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
160 #define VIEWER_MENU BUTTON_F1
161 #define VIEWER_AUTOSCROLL BUTTON_PLAY
162 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
163 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
164 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
165 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
166 #define VIEWER_BOOKMARK BUTTON_F2
168 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
169 #define VIEWER_QUIT BUTTON_OFF
170 #define VIEWER_PAGE_UP BUTTON_UP
171 #define VIEWER_PAGE_DOWN BUTTON_DOWN
172 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
173 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
174 #define VIEWER_MENU BUTTON_F1
175 #define VIEWER_AUTOSCROLL BUTTON_SELECT
176 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
177 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
178 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
179 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
180 #define VIEWER_BOOKMARK BUTTON_F2
183 #elif CONFIG_KEYPAD == ONDIO_PAD
184 #define VIEWER_QUIT BUTTON_OFF
185 #define VIEWER_PAGE_UP BUTTON_UP
186 #define VIEWER_PAGE_DOWN BUTTON_DOWN
187 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
188 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
189 #define VIEWER_MENU (BUTTON_MENU|BUTTON_REPEAT)
190 #define VIEWER_AUTOSCROLL_PRE BUTTON_MENU
191 #define VIEWER_AUTOSCROLL (BUTTON_MENU|BUTTON_REL)
192 #define VIEWER_BOOKMARK (BUTTON_MENU|BUTTON_OFF)
195 #elif CONFIG_KEYPAD == PLAYER_PAD
196 #define VIEWER_QUIT BUTTON_STOP
197 #define VIEWER_PAGE_UP BUTTON_LEFT
198 #define VIEWER_PAGE_DOWN BUTTON_RIGHT
199 #define VIEWER_SCREEN_LEFT (BUTTON_ON|BUTTON_LEFT)
200 #define VIEWER_SCREEN_RIGHT (BUTTON_ON|BUTTON_RIGHT)
201 #define VIEWER_MENU BUTTON_MENU
202 #define VIEWER_AUTOSCROLL BUTTON_PLAY
203 #define VIEWER_BOOKMARK BUTTON_ON
205 /* iRiver H1x0 && H3x0 keys */
206 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
207 (CONFIG_KEYPAD == IRIVER_H300_PAD)
208 #define VIEWER_QUIT BUTTON_OFF
209 #define VIEWER_PAGE_UP BUTTON_UP
210 #define VIEWER_PAGE_DOWN BUTTON_DOWN
211 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
212 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
213 #define VIEWER_MENU BUTTON_MODE
214 #define VIEWER_AUTOSCROLL BUTTON_SELECT
215 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
216 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
217 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
218 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
219 #define VIEWER_BOOKMARK (BUTTON_ON | BUTTON_SELECT)
221 #define VIEWER_RC_QUIT BUTTON_RC_STOP
224 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
225 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
226 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
227 #define VIEWER_QUIT_PRE BUTTON_SELECT
228 #define VIEWER_QUIT (BUTTON_SELECT | BUTTON_MENU)
229 #define VIEWER_PAGE_UP BUTTON_SCROLL_BACK
230 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_FWD
231 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
232 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
233 #define VIEWER_MENU BUTTON_MENU
234 #define VIEWER_AUTOSCROLL BUTTON_PLAY
235 #define VIEWER_BOOKMARK BUTTON_SELECT
238 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
239 #define VIEWER_QUIT BUTTON_PLAY
240 #define VIEWER_PAGE_UP BUTTON_UP
241 #define VIEWER_PAGE_DOWN BUTTON_DOWN
242 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
243 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
244 #define VIEWER_MENU BUTTON_MODE
245 #define VIEWER_AUTOSCROLL BUTTON_SELECT
246 #define VIEWER_BOOKMARK (BUTTON_LEFT|BUTTON_SELECT)
249 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
250 #define VIEWER_QUIT BUTTON_POWER
251 #define VIEWER_PAGE_UP BUTTON_UP
252 #define VIEWER_PAGE_DOWN BUTTON_DOWN
253 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
254 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
255 #define VIEWER_MENU BUTTON_SELECT
256 #define VIEWER_AUTOSCROLL BUTTON_PLAY
257 #define VIEWER_BOOKMARK BUTTON_REC
260 #elif CONFIG_KEYPAD == GIGABEAT_PAD
261 #define VIEWER_QUIT BUTTON_POWER
262 #define VIEWER_PAGE_UP BUTTON_UP
263 #define VIEWER_PAGE_DOWN BUTTON_DOWN
264 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
265 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
266 #define VIEWER_MENU BUTTON_MENU
267 #define VIEWER_AUTOSCROLL BUTTON_A
268 #define VIEWER_BOOKMARK BUTTON_SELECT
270 /* Sansa E200 keys */
271 #elif CONFIG_KEYPAD == SANSA_E200_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_SELECT
278 #define VIEWER_AUTOSCROLL BUTTON_REC
279 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
280 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
281 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
283 /* Sansa Fuze keys */
284 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
285 #define VIEWER_QUIT (BUTTON_HOME|BUTTON_REPEAT)
286 #define VIEWER_PAGE_UP BUTTON_UP
287 #define VIEWER_PAGE_DOWN BUTTON_DOWN
288 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
289 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
290 #define VIEWER_MENU BUTTON_SELECT|BUTTON_REPEAT
291 #define VIEWER_AUTOSCROLL BUTTON_SELECT|BUTTON_DOWN
292 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
293 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
294 #define VIEWER_BOOKMARK BUTTON_SELECT
296 /* Sansa C200 keys */
297 #elif CONFIG_KEYPAD == SANSA_C200_PAD
298 #define VIEWER_QUIT BUTTON_POWER
299 #define VIEWER_PAGE_UP BUTTON_VOL_UP
300 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
301 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
302 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
303 #define VIEWER_MENU BUTTON_SELECT
304 #define VIEWER_AUTOSCROLL BUTTON_REC
305 #define VIEWER_LINE_UP BUTTON_UP
306 #define VIEWER_LINE_DOWN BUTTON_DOWN
307 #define VIEWER_BOOKMARK (BUTTON_DOWN | BUTTON_SELECT)
309 /* Sansa Clip keys */
310 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
311 #define VIEWER_QUIT BUTTON_POWER
312 #define VIEWER_PAGE_UP BUTTON_VOL_UP
313 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
314 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
315 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
316 #define VIEWER_MENU BUTTON_SELECT
317 #define VIEWER_AUTOSCROLL BUTTON_HOME
318 #define VIEWER_LINE_UP BUTTON_UP
319 #define VIEWER_LINE_DOWN BUTTON_DOWN
320 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
322 /* Sansa M200 keys */
323 #elif CONFIG_KEYPAD == SANSA_M200_PAD
324 #define VIEWER_QUIT BUTTON_POWER
325 #define VIEWER_PAGE_UP BUTTON_VOL_UP
326 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
327 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
328 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
329 #define VIEWER_MENU (BUTTON_SELECT | BUTTON_UP)
330 #define VIEWER_AUTOSCROLL (BUTTON_SELECT | BUTTON_REL)
331 #define VIEWER_LINE_UP BUTTON_UP
332 #define VIEWER_LINE_DOWN BUTTON_DOWN
333 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
335 /* iriver H10 keys */
336 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
337 #define VIEWER_QUIT BUTTON_POWER
338 #define VIEWER_PAGE_UP BUTTON_SCROLL_UP
339 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_DOWN
340 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
341 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
342 #define VIEWER_MENU BUTTON_REW
343 #define VIEWER_AUTOSCROLL BUTTON_PLAY
344 #define VIEWER_BOOKMARK BUTTON_FF
347 #elif CONFIG_KEYPAD == MROBE500_PAD
348 #define VIEWER_QUIT BUTTON_POWER
349 #define VIEWER_PAGE_UP BUTTON_RC_PLAY
350 #define VIEWER_PAGE_DOWN BUTTON_RC_DOWN
351 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
352 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
353 #define VIEWER_MENU BUTTON_RC_HEART
354 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
355 #define VIEWER_BOOKMARK BUTTON_CENTER
358 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
359 #define VIEWER_QUIT BUTTON_BACK
360 #define VIEWER_PAGE_UP BUTTON_PREV
361 #define VIEWER_PAGE_DOWN BUTTON_NEXT
362 #define VIEWER_SCREEN_LEFT (BUTTON_PLAY | BUTTON_LEFT)
363 #define VIEWER_SCREEN_RIGHT (BUTTON_PLAY | BUTTON_RIGHT)
364 #define VIEWER_MENU BUTTON_MENU
365 #define VIEWER_AUTOSCROLL_PRE BUTTON_PLAY
366 #define VIEWER_AUTOSCROLL (BUTTON_PLAY|BUTTON_REL)
367 #define VIEWER_LINE_UP BUTTON_UP
368 #define VIEWER_LINE_DOWN BUTTON_DOWN
369 #define VIEWER_COLUMN_LEFT BUTTON_LEFT
370 #define VIEWER_COLUMN_RIGHT BUTTON_RIGHT
371 #define VIEWER_BOOKMARK BUTTON_SELECT
374 #elif CONFIG_KEYPAD == MROBE100_PAD
375 #define VIEWER_QUIT BUTTON_POWER
376 #define VIEWER_PAGE_UP BUTTON_UP
377 #define VIEWER_PAGE_DOWN BUTTON_DOWN
378 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
379 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
380 #define VIEWER_MENU BUTTON_MENU
381 #define VIEWER_AUTOSCROLL BUTTON_DISPLAY
382 #define VIEWER_BOOKMARK BUTTON_SELECT
385 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
386 #define VIEWER_QUIT BUTTON_REC
387 #define VIEWER_PAGE_UP BUTTON_RC_VOL_UP
388 #define VIEWER_PAGE_DOWN BUTTON_RC_VOL_DOWN
389 #define VIEWER_SCREEN_LEFT BUTTON_RC_REW
390 #define VIEWER_SCREEN_RIGHT BUTTON_RC_FF
391 #define VIEWER_MENU BUTTON_RC_MENU
392 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
393 #define VIEWER_RC_QUIT BUTTON_RC_REC
394 #define VIEWER_BOOKMARK BUTTON_RC_PLAY
397 #elif CONFIG_KEYPAD == COWON_D2_PAD
398 #define VIEWER_QUIT BUTTON_POWER
399 #define VIEWER_MENU BUTTON_MENU
400 #define VIEWER_PAGE_UP BUTTON_MINUS
401 #define VIEWER_PAGE_DOWN BUTTON_PLUS
402 #define VIEWER_BOOKMARK (BUTTON_MENU|BUTTON_PLUS)
404 #elif CONFIG_KEYPAD == IAUDIO67_PAD
405 #define VIEWER_QUIT BUTTON_POWER
406 #define VIEWER_PAGE_UP BUTTON_VOLUP
407 #define VIEWER_PAGE_DOWN BUTTON_VOLDOWN
408 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
409 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
410 #define VIEWER_MENU BUTTON_MENU
411 #define VIEWER_AUTOSCROLL BUTTON_PLAY
412 #define VIEWER_RC_QUIT BUTTON_STOP
413 #define VIEWER_BOOKMARK (BUTTON_LEFT|BUTTON_PLAY)
415 /* Creative Zen Vision:M keys */
416 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
417 #define VIEWER_QUIT BUTTON_BACK
418 #define VIEWER_PAGE_UP BUTTON_UP
419 #define VIEWER_PAGE_DOWN BUTTON_DOWN
420 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
421 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
422 #define VIEWER_MENU BUTTON_MENU
423 #define VIEWER_AUTOSCROLL BUTTON_SELECT
424 #define VIEWER_BOOKMARK BUTTON_PLAY
426 /* Philips HDD1630 keys */
427 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
428 #define VIEWER_QUIT BUTTON_POWER
429 #define VIEWER_PAGE_UP BUTTON_UP
430 #define VIEWER_PAGE_DOWN BUTTON_DOWN
431 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
432 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
433 #define VIEWER_MENU BUTTON_MENU
434 #define VIEWER_AUTOSCROLL BUTTON_VIEW
435 #define VIEWER_BOOKMARK BUTTON_SELECT
437 /* Philips SA9200 keys */
438 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
439 #define VIEWER_QUIT BUTTON_POWER
440 #define VIEWER_PAGE_UP BUTTON_UP
441 #define VIEWER_PAGE_DOWN BUTTON_DOWN
442 #define VIEWER_SCREEN_LEFT BUTTON_PREV
443 #define VIEWER_SCREEN_RIGHT BUTTON_NEXT
444 #define VIEWER_MENU BUTTON_MENU
445 #define VIEWER_AUTOSCROLL BUTTON_PLAY
446 #define VIEWER_BOOKMARK BUTTON_RIGHT
448 /* Onda VX747 keys */
449 #elif CONFIG_KEYPAD == ONDAVX747_PAD
450 #define VIEWER_QUIT BUTTON_POWER
451 #define VIEWER_MENU BUTTON_MENU
452 #define VIEWER_BOOKMARK BUTTON_RIGHT
454 /* Onda VX777 keys */
455 #elif CONFIG_KEYPAD == ONDAVX777_PAD
456 #define VIEWER_QUIT BUTTON_POWER
457 #define VIEWER_BOOKMARK BUTTON_RIGHT
459 /* SAMSUNG YH-820 / YH-920 / YH-925 keys */
460 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
461 #define VIEWER_QUIT BUTTON_REC
462 #define VIEWER_PAGE_UP BUTTON_UP
463 #define VIEWER_PAGE_DOWN BUTTON_DOWN
464 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
465 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
466 #define VIEWER_MENU BUTTON_PLAY
467 #define VIEWER_AUTOSCROLL BUTTON_REW
468 #define VIEWER_BOOKMARK BUTTON_FFWD
470 /* Packard Bell Vibe 500 keys */
471 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
472 #define VIEWER_QUIT BUTTON_REC
473 #define VIEWER_PAGE_UP BUTTON_OK
474 #define VIEWER_PAGE_DOWN BUTTON_CANCEL
475 #define VIEWER_LINE_UP BUTTON_UP
476 #define VIEWER_LINE_DOWN BUTTON_DOWN
477 #define VIEWER_SCREEN_LEFT BUTTON_PREV
478 #define VIEWER_SCREEN_RIGHT BUTTON_NEXT
479 #define VIEWER_MENU BUTTON_MENU
480 #define VIEWER_AUTOSCROLL BUTTON_PLAY
481 #define VIEWER_BOOKMARK BUTTON_POWER
484 #error No keymap defined!
487 #ifdef HAVE_TOUCHSCREEN
489 #define VIEWER_QUIT2 BUTTON_TOPLEFT
491 #define VIEWER_QUIT BUTTON_TOPLEFT
493 #ifdef VIEWER_PAGE_UP
494 #define VIEWER_PAGE_UP2 BUTTON_TOPMIDDLE
496 #define VIEWER_PAGE_UP BUTTON_TOPMIDDLE
498 #ifdef VIEWER_PAGE_DOWN
499 #define VIEWER_PAGE_DOWN2 BUTTON_BOTTOMMIDDLE
501 #define VIEWER_PAGE_DOWN BUTTON_BOTTOMMIDDLE
503 #ifndef VIEWER_SCREEN_LEFT
504 #define VIEWER_SCREEN_LEFT BUTTON_MIDLEFT
506 #ifndef VIEWER_SCREEN_RIGHT
507 #define VIEWER_SCREEN_RIGHT BUTTON_MIDRIGHT
510 #define VIEWER_MENU2 BUTTON_TOPRIGHT
512 #define VIEWER_MENU BUTTON_TOPRIGHT
514 #ifndef VIEWER_AUTOSCROLL
515 #define VIEWER_AUTOSCROLL BUTTON_CENTER
519 /* stuff for the bookmarking */
520 struct bookmark_info
{
537 REFLOW
, /* won't be set on charcell LCD, must be last */
545 enum codepages encoding
;
577 int autoscroll_speed
;
579 unsigned char font
[MAX_PATH
];
583 VIEWER_FONT_MENU
= 0,
587 struct preferences prefs
;
588 struct preferences old_prefs
;
590 static unsigned char *buffer
;
591 static long buffer_size
;
592 static long block_size
= 0x1000;
593 static unsigned char line_break
[] = {0,0x20,9,0xB,0xC,'-'};
594 static int display_columns
; /* number of (pixel) columns on the display */
595 static int display_lines
; /* number of lines on the display */
596 static int draw_columns
; /* number of (pixel) columns available for text */
597 static int par_indent_spaces
; /* number of spaces to indent first paragraph */
599 static const char *file_name
;
600 static long file_size
;
601 static long start_position
; /* position in the file after the viewer is started */
602 static bool mac_text
;
603 static long file_pos
; /* Position of the top of the buffer in the file */
604 static long last_file_pos
;
605 static unsigned char *buffer_end
; /*Set to BUFFER_END() when file_pos changes*/
606 static int max_line_len
;
607 static int max_width
;
608 static int max_columns
;
609 static int cline
= 1;
610 static int cpage
= 1;
611 static int lpage
= 0;
612 static unsigned char *screen_top_ptr
;
613 static unsigned char *next_screen_ptr
;
614 static unsigned char *next_screen_to_draw_ptr
;
615 static unsigned char *next_line_ptr
;
616 static unsigned char *last_screen_top_ptr
= NULL
;
617 #ifdef HAVE_LCD_BITMAP
618 static struct font
*pf
;
619 static int header_height
= 0;
620 static int footer_height
= 0;
622 struct bookmark_info bookmarks
[MAX_BOOKMARKS
];
623 static int bookmark_count
;
626 #define BOM "\xef\xbb\xbf"
629 static bool is_bom
= false;
631 static int glyph_width(int ch
)
636 #ifdef HAVE_LCD_BITMAP
637 return rb
->font_get_width(pf
, ch
);
643 static unsigned char* get_ucs(const unsigned char* str
, unsigned short* ch
)
645 unsigned char utf8_tmp
[6];
648 if (prefs
.encoding
== UTF_8
)
649 return (unsigned char*)rb
->utf8decode(str
, ch
);
651 count
= BUFFER_OOB(str
+2)? 1:2;
652 rb
->iso_decode(str
, utf8_tmp
, prefs
.encoding
, count
);
653 rb
->utf8decode(utf8_tmp
, ch
);
655 #ifdef HAVE_LCD_BITMAP
656 if (prefs
.encoding
>= SJIS
&& *str
>= 0x80
657 && !(prefs
.encoding
== SJIS
&& *str
> 0xA0 && *str
< 0xE0))
658 return (unsigned char*)str
+2;
661 return (unsigned char*)str
+1;
664 static unsigned char *decode2utf8(const unsigned char *src
, unsigned char *dst
,
665 int skip_width
, int disp_width
)
668 const unsigned char *oldstr
;
669 const unsigned char *str
= src
;
670 unsigned char *utf8
= dst
;
676 str
= get_ucs(oldstr
, &ch
);
677 width
+= glyph_width(ch
);
678 if (width
> skip_width
)
687 str
= get_ucs(str
, &ch
);
688 width
+= glyph_width(ch
);
689 if (width
> disp_width
)
692 utf8
= rb
->utf8encode(ch
, utf8
);
698 static void calc_max_width(void)
700 if (prefs
.view_mode
== NARROW
)
702 max_columns
= NARROW_MAX_COLUMNS
;
703 max_width
= draw_columns
;
707 max_columns
= WIDE_MAX_COLUMNS
;
708 max_width
= 2 * draw_columns
;
715 #define ADVANCE_COUNTERS(c) { width += glyph_width(c); k++; }
716 #define LINE_IS_FULL ((k>=max_columns-1) ||( width >= max_width))
717 #define LINE_IS_NOT_FULL ((k<max_columns-1) &&( width < max_width))
718 static unsigned char* crop_at_width(const unsigned char* p
)
722 const unsigned char *oldp
= p
;
726 while (LINE_IS_NOT_FULL
) {
731 ADVANCE_COUNTERS(ch
);
734 return (unsigned char*)oldp
;
737 static unsigned char* find_first_feed(const unsigned char* p
, int size
)
741 for (i
=0; i
< size
; i
++)
743 return (unsigned char*) p
+i
;
748 static unsigned char* find_last_feed(const unsigned char* p
, int size
)
752 for (i
=size
-1; i
>=0; i
--)
754 return (unsigned char*) p
+i
;
759 static unsigned char* find_last_space(const unsigned char* p
, int size
)
763 k
= (prefs
.line_mode
==JOIN
) || (prefs
.line_mode
==REFLOW
) ? 0:1;
765 if (!BUFFER_OOB(&p
[size
]))
766 for (j
=k
; j
< ((int) sizeof(line_break
)) - 1; j
++)
767 if (p
[size
] == line_break
[j
])
768 return (unsigned char*) p
+size
;
770 for (i
=size
-1; i
>=0; i
--)
771 for (j
=k
; j
< (int) sizeof(line_break
); j
++)
773 if (!((p
[i
] == '-') && (prefs
.word_mode
== WRAP
)))
774 if (p
[i
] == line_break
[j
])
775 return (unsigned char*) p
+i
;
781 static unsigned char* find_next_line(const unsigned char* cur_line
, bool *is_short
)
783 const unsigned char *next_line
= NULL
;
784 int size
, i
, j
, k
, width
, search_len
, spaces
, newlines
;
788 if (is_short
!= NULL
)
791 if BUFFER_OOB(cur_line
)
794 if (prefs
.view_mode
== WIDE
) {
795 search_len
= MAX_WIDTH
;
797 else { /* prefs.view_mode == NARROW */
798 search_len
= crop_at_width(cur_line
) - cur_line
;
801 size
= BUFFER_OOB(cur_line
+search_len
) ? buffer_end
-cur_line
: search_len
;
803 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
)) {
804 /* Need to scan ahead and possibly increase search_len and size,
805 or possibly set next_line at second hard return in a row. */
808 for (j
=k
=width
=spaces
=newlines
=0; ; j
++) {
809 if (BUFFER_OOB(cur_line
+j
))
812 size
= search_len
= j
;
819 if (prefs
.line_mode
== REFLOW
) {
822 next_line
= cur_line
+ size
;
823 return (unsigned char*) next_line
;
825 if (j
==0) /* i=1 is intentional */
826 for (i
=0; i
<par_indent_spaces
; i
++)
827 ADVANCE_COUNTERS(' ');
829 if (!first_chars
) spaces
++;
835 next_line
= cur_line
+ size
- spaces
;
836 if (next_line
!= cur_line
)
837 return (unsigned char*) next_line
;
843 if (BUFFER_OOB(cur_line
+size
) || size
> 2*search_len
)
846 spaces
= first_chars
? 0:1;
850 if (prefs
.line_mode
==JOIN
|| newlines
>0) {
853 ADVANCE_COUNTERS(' ');
855 size
= search_len
= j
;
861 /* REFLOW, multiple spaces between words: count only
862 * one. If more are needed, they will be added
866 ADVANCE_COUNTERS(' ');
868 size
= search_len
= j
;
879 /* find first hard return */
880 next_line
= find_first_feed(cur_line
, size
);
883 if (next_line
== NULL
)
884 if (size
== search_len
) {
885 if (prefs
.word_mode
== WRAP
) /* Find last space */
886 next_line
= find_last_space(cur_line
, size
);
888 if (next_line
== NULL
)
889 next_line
= crop_at_width(cur_line
);
891 if (prefs
.word_mode
== WRAP
)
893 i
<WRAP_TRIM
&& isspace(next_line
[0]) && !BUFFER_OOB(next_line
);
898 if (prefs
.line_mode
== EXPAND
)
899 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
900 if (next_line
[0] == 0)
901 if (next_line
!= cur_line
)
902 return (unsigned char*) next_line
;
904 /* If next_line is pointing to a zero, increment it; i.e.,
905 leave the terminator at the end of cur_line. If pointing
906 to a hyphen, increment only if there is room to display
907 the hyphen on current line (won't apply in WIDE mode,
908 since it's guarenteed there won't be room). */
909 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
910 if (next_line
[0] == 0)/* ||
911 (next_line[0] == '-' && next_line-cur_line < draw_columns)) */
914 if (BUFFER_OOB(next_line
))
916 if (BUFFER_EOF() && next_line
!= cur_line
)
917 return (unsigned char*) next_line
;
924 return (unsigned char*) next_line
;
927 static unsigned char* find_prev_line(const unsigned char* cur_line
)
929 const unsigned char *prev_line
= NULL
;
930 const unsigned char *p
;
932 if BUFFER_OOB(cur_line
)
935 /* To wrap consistently at the same places, we must
936 start with a known hard return, then work downwards.
937 We can either search backwards for a hard return,
938 or simply start wrapping downwards from top of buffer.
939 If current line is not near top of buffer, this is
940 a file with long lines (paragraphs). We would need to
941 read earlier sectors before we could decide how to
942 properly wrap the lines above the current line, but
943 it probably is not worth the disk access. Instead,
944 start with top of buffer and wrap down from there.
945 This may result in some lines wrapping at different
946 points from where they wrap when scrolling down.
947 If buffer is at top of file, start at top of buffer. */
949 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
))
950 prev_line
= p
= NULL
;
952 prev_line
= p
= find_last_feed(buffer
, cur_line
-buffer
-1);
953 /* Null means no line feeds in buffer above current line. */
955 if (prev_line
== NULL
)
956 if (BUFFER_BOF() || cur_line
- buffer
> READ_PREV_ZONE
)
957 prev_line
= p
= buffer
;
958 /* (else return NULL and read previous block) */
960 /* Wrap downwards until too far, then use the one before. */
961 while (p
!= NULL
&& p
< cur_line
) {
963 p
= find_next_line(prev_line
, NULL
);
966 if (BUFFER_OOB(prev_line
))
969 return (unsigned char*) prev_line
;
972 static void check_bom(void)
974 unsigned char bom
[BOM_SIZE
];
975 off_t orig
= rb
->lseek(fd
, 0, SEEK_CUR
);
979 rb
->lseek(fd
, 0, SEEK_SET
);
981 if (rb
->read(fd
, bom
, BOM_SIZE
) == BOM_SIZE
)
982 is_bom
= !memcmp(bom
, BOM
, BOM_SIZE
);
984 rb
->lseek(fd
, orig
, SEEK_SET
);
987 static void fill_buffer(long pos
, unsigned char* buf
, unsigned size
)
989 /* Read from file and preprocess the data */
990 /* To minimize disk access, always read on sector boundaries */
992 bool found_CR
= false;
993 off_t offset
= rb
->lseek(fd
, pos
, SEEK_SET
);
995 if (offset
== 0 && prefs
.encoding
== UTF_8
&& is_bom
)
996 rb
->lseek(fd
, BOM_SIZE
, SEEK_SET
);
998 numread
= rb
->read(fd
, buf
, size
);
1000 rb
->button_clear_queue(); /* clear button queue */
1002 for(i
= 0; i
< numread
; i
++) {
1019 case 0: /* No break between case 0 and default, intentionally */
1032 static int viewer_find_bookmark(int page
, int line
)
1036 for (i
= 0; i
< bookmark_count
; i
++)
1038 if (bookmarks
[i
].page
== page
&& bookmarks
[i
].line
== line
)
1044 static int read_and_synch(int direction
)
1046 /* Read next (or prev) block, and reposition global pointers. */
1047 /* direction: 1 for down (i.e., further into file), -1 for up */
1048 int move_size
, move_vector
, offset
;
1049 unsigned char *fill_buf
;
1051 if (direction
== -1) /* up */ {
1052 move_size
= SMALL_BLOCK_SIZE
;
1054 fill_buf
= TOP_SECTOR
;
1055 rb
->memcpy(BOTTOM_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
1056 rb
->memcpy(MID_SECTOR
, TOP_SECTOR
, SMALL_BLOCK_SIZE
);
1059 if (prefs
.view_mode
== WIDE
) {
1060 /* WIDE mode needs more buffer so we have to read smaller blocks */
1061 move_size
= SMALL_BLOCK_SIZE
;
1062 offset
= LARGE_BLOCK_SIZE
;
1063 fill_buf
= BOTTOM_SECTOR
;
1064 rb
->memcpy(TOP_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
1065 rb
->memcpy(MID_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
1068 move_size
= LARGE_BLOCK_SIZE
;
1069 offset
= SMALL_BLOCK_SIZE
;
1070 fill_buf
= MID_SECTOR
;
1071 rb
->memcpy(TOP_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
1074 move_vector
= direction
* move_size
;
1075 screen_top_ptr
-= move_vector
;
1076 file_pos
+= move_vector
;
1077 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1078 fill_buffer(file_pos
+ offset
, fill_buf
, move_size
);
1082 static void get_next_line_position(unsigned char **line_begin
,
1083 unsigned char **line_end
,
1088 *line_begin
= *line_end
;
1089 *line_end
= find_next_line(*line_begin
, is_short
);
1091 if (*line_end
== NULL
&& !BUFFER_EOF())
1093 resynch_move
= read_and_synch(1); /* Read block & move ptrs */
1094 *line_begin
-= resynch_move
;
1095 if (next_line_ptr
> buffer
)
1096 next_line_ptr
-= resynch_move
;
1098 *line_end
= find_next_line(*line_begin
, is_short
);
1102 static void increment_current_line(void)
1104 if (cline
< display_lines
)
1106 else if (cpage
< MAX_PAGE
)
1113 static void decrement_current_line(void)
1120 cline
= display_lines
;
1124 static void viewer_scroll_up(void)
1128 p
= find_prev_line(screen_top_ptr
);
1129 if (p
== NULL
&& !BUFFER_BOF()) {
1131 p
= find_prev_line(screen_top_ptr
);
1136 decrement_current_line();
1139 static void viewer_scroll_down(bool autoscroll
)
1144 if (next_line_ptr
!= NULL
)
1145 screen_top_ptr
= next_line_ptr
;
1147 if (prefs
.scroll_mode
== LINE
|| autoscroll
)
1148 increment_current_line();
1151 static void viewer_scroll_to_top_line(void)
1155 for (line
= cline
; line
> 1; line
--)
1159 #ifdef HAVE_LCD_BITMAP
1160 static void viewer_scrollbar(void) {
1161 int items
, min_shown
, max_shown
, sb_begin_y
, sb_height
;
1163 items
= (int) file_size
; /* (SH1 int is same as long) */
1164 min_shown
= (int) file_pos
+ (screen_top_ptr
- buffer
);
1166 if (next_screen_ptr
== NULL
)
1169 max_shown
= min_shown
+ (next_screen_ptr
- screen_top_ptr
);
1171 sb_begin_y
= header_height
;
1172 sb_height
= LCD_HEIGHT
- header_height
- footer_height
;
1174 rb
->gui_scrollbar_draw(rb
->screens
[SCREEN_MAIN
],0, sb_begin_y
,
1175 SCROLLBAR_WIDTH
-1, sb_height
,
1176 items
, min_shown
, max_shown
, VERTICAL
);
1180 #ifdef HAVE_LCD_BITMAP
1181 static void viewer_show_header(void)
1183 if (prefs
.header_mode
== HD_SBAR
|| prefs
.header_mode
== HD_BOTH
)
1184 rb
->gui_syncstatusbar_draw(rb
->statusbars
, true);
1186 if (prefs
.header_mode
== HD_PATH
|| prefs
.header_mode
== HD_BOTH
)
1187 rb
->lcd_putsxy(0, header_height
- pf
->height
, file_name
);
1190 static void viewer_show_footer(void)
1192 if (prefs
.footer_mode
== FT_SBAR
|| prefs
.footer_mode
== FT_BOTH
)
1193 rb
->gui_syncstatusbar_draw(rb
->statusbars
, true);
1195 if (prefs
.footer_mode
== FT_PAGE
|| prefs
.footer_mode
== FT_BOTH
)
1197 unsigned char buf
[12];
1200 rb
->snprintf(buf
, sizeof(buf
), "%d", cpage
);
1202 rb
->snprintf(buf
, sizeof(buf
), "%d - %d", cpage
, cpage
+1);
1204 rb
->lcd_putsxy(0, LCD_HEIGHT
- footer_height
, buf
);
1209 static void viewer_draw(int col
)
1211 int i
, j
, k
, line_len
, line_width
, spaces
, left_col
=0;
1212 int width
, extra_spaces
, indent_spaces
, spaces_per_word
;
1213 bool multiple_spacing
, line_is_short
;
1215 unsigned char *str
, *oldstr
;
1216 unsigned char *line_begin
;
1217 unsigned char *line_end
;
1219 unsigned char scratch_buffer
[max_columns
+ 1];
1220 unsigned char utf8_buffer
[max_columns
*4 + 1];
1221 unsigned char *endptr
;
1223 /* If col==-1 do all calculations but don't display */
1225 #ifdef HAVE_LCD_BITMAP
1226 left_col
= prefs
.need_scrollbar
? SCROLLBAR_WIDTH
:0;
1230 rb
->lcd_clear_display();
1233 line_begin
= line_end
= screen_top_ptr
;
1235 for (i
= 0; i
< display_lines
; i
++) {
1236 if (BUFFER_OOB(line_end
))
1239 break; /* Happens after display last line at BUFFER_EOF() */
1241 if (lpage
== 0 && cline
== 1)
1244 last_screen_top_ptr
= screen_top_ptr
;
1245 last_file_pos
= file_pos
;
1249 get_next_line_position(&line_begin
, &line_end
, &line_is_short
);
1250 if (line_end
== NULL
)
1252 if (BUFFER_OOB(line_begin
))
1254 line_end
= buffer_end
+ 1;
1257 line_len
= line_end
- line_begin
;
1259 /* calculate line_len */
1260 str
= oldstr
= line_begin
;
1262 while (str
< line_end
) {
1264 str
= crop_at_width(str
);
1267 line_width
= j
*draw_columns
;
1268 while (oldstr
< line_end
) {
1269 oldstr
= get_ucs(oldstr
, &ch
);
1270 line_width
+= glyph_width(ch
);
1273 if (prefs
.line_mode
== JOIN
) {
1274 if (line_begin
[0] == 0) {
1276 if (prefs
.word_mode
== CHOP
)
1281 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
1282 if (k
== max_columns
)
1292 scratch_buffer
[k
++] = ' ';
1297 scratch_buffer
[k
++] = ' ';
1298 if (k
== max_columns
- 1)
1301 scratch_buffer
[k
++] = c
;
1306 scratch_buffer
[k
] = 0;
1307 endptr
= decode2utf8(scratch_buffer
, utf8_buffer
, col
, draw_columns
);
1311 else if (prefs
.line_mode
== REFLOW
) {
1312 if (line_begin
[0] == 0) {
1314 if (prefs
.word_mode
== CHOP
)
1321 if (!line_is_short
) {
1322 multiple_spacing
= false;
1324 for (str
= line_begin
; str
< line_end
; ) {
1325 str
= get_ucs(str
, &ch
);
1329 if ((str
== line_begin
) && (prefs
.word_mode
==WRAP
))
1330 /* special case: indent the paragraph,
1331 * don't count spaces */
1332 indent_spaces
= par_indent_spaces
;
1333 else if (!multiple_spacing
)
1335 multiple_spacing
= true;
1338 multiple_spacing
= false;
1339 width
+= glyph_width(ch
);
1343 if (multiple_spacing
) spaces
--;
1346 /* total number of spaces to insert between words */
1347 extra_spaces
= (max_width
-width
)/glyph_width(' ')
1349 /* number of spaces between each word*/
1350 spaces_per_word
= extra_spaces
/ spaces
;
1351 /* number of words with n+1 spaces (to fill up) */
1352 extra_spaces
= extra_spaces
% spaces
;
1353 if (spaces_per_word
> 2) { /* too much spacing is awful */
1354 spaces_per_word
= 3;
1357 } else { /* this doesn't matter much... no spaces anyway */
1358 spaces_per_word
= extra_spaces
= 0;
1360 } else { /* end of a paragraph: don't fill line */
1361 spaces_per_word
= 1;
1365 multiple_spacing
= false;
1366 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
1367 if (k
== max_columns
)
1374 if (j
==0 && prefs
.word_mode
==WRAP
) { /* indent paragraph */
1375 for (j
=0; j
<par_indent_spaces
; j
++)
1376 scratch_buffer
[k
++] = ' ';
1379 else if (!multiple_spacing
) {
1380 for (width
= spaces
<extra_spaces
? -1:0; width
< spaces_per_word
; width
++)
1381 scratch_buffer
[k
++] = ' ';
1384 multiple_spacing
= true;
1387 scratch_buffer
[k
++] = c
;
1388 multiple_spacing
= false;
1393 scratch_buffer
[k
] = 0;
1394 endptr
= decode2utf8(scratch_buffer
, utf8_buffer
, col
, draw_columns
);
1398 else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */
1400 if (line_width
> col
) {
1401 str
= oldstr
= line_begin
;
1404 while( (width
<draw_columns
) && (oldstr
<line_end
) )
1406 oldstr
= get_ucs(oldstr
, &ch
);
1408 k
-= glyph_width(ch
);
1409 line_begin
= oldstr
;
1411 width
+= glyph_width(ch
);
1415 if(prefs
.view_mode
==WIDE
)
1416 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1417 prefs
.encoding
, oldstr
-line_begin
);
1419 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1420 prefs
.encoding
, line_end
-line_begin
);
1424 if (col
!= -1 && line_width
> col
)
1426 int dpage
= (cline
+i
<= display_lines
)?cpage
:cpage
+1;
1427 int dline
= cline
+i
- ((cline
+i
<= display_lines
)?0:display_lines
);
1428 bool bflag
= (viewer_find_bookmark(dpage
, dline
) >= 0);
1429 #ifdef HAVE_LCD_BITMAP
1430 int dy
= i
* pf
->height
+ header_height
;
1433 #ifdef HAVE_LCD_BITMAP
1435 rb
->lcd_set_drawmode(DRMODE_BG
|DRMODE_FG
);
1436 rb
->lcd_fillrect(left_col
, dy
, LCD_WIDTH
, pf
->height
);
1437 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
1439 rb
->lcd_putsxy(left_col
, dy
, utf8_buffer
);
1440 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1443 rb
->lcd_puts(left_col
, i
, BOOKMARK_ICON
);
1445 rb
->lcd_puts(left_col
+1, i
, utf8_buffer
);
1448 if (line_width
> max_line_len
)
1449 max_line_len
= line_width
;
1452 next_line_ptr
= line_end
;
1454 next_screen_ptr
= line_end
;
1455 if (BUFFER_OOB(next_screen_ptr
))
1456 next_screen_ptr
= NULL
;
1458 #ifdef HAVE_LCD_BITMAP
1459 next_screen_to_draw_ptr
= prefs
.page_mode
==OVERLAP
? line_begin
: next_screen_ptr
;
1461 if (prefs
.need_scrollbar
)
1464 next_screen_to_draw_ptr
= next_screen_ptr
;
1467 #ifdef HAVE_LCD_BITMAP
1469 viewer_show_header();
1472 viewer_show_footer();
1479 static void viewer_top(void)
1481 /* Read top of file into buffer
1482 and point screen pointer to top */
1485 rb
->splash(0, "Loading...");
1488 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1489 fill_buffer(0, buffer
, buffer_size
);
1492 screen_top_ptr
= buffer
;
1497 static void viewer_bottom(void)
1499 unsigned char *line_begin
;
1500 unsigned char *line_end
;
1502 rb
->splash(0, "Loading...");
1504 if (last_screen_top_ptr
)
1508 screen_top_ptr
= last_screen_top_ptr
;
1509 file_pos
= last_file_pos
;
1510 fill_buffer(file_pos
, buffer
, buffer_size
);
1511 buffer_end
= BUFFER_END();
1515 line_end
= screen_top_ptr
;
1517 while (!BUFFER_EOF() || !BUFFER_OOB(line_end
))
1519 get_next_line_position(&line_begin
, &line_end
, NULL
);
1520 if (line_end
== NULL
)
1523 increment_current_line();
1525 screen_top_ptr
= line_end
;
1529 last_screen_top_ptr
= screen_top_ptr
;
1530 last_file_pos
= file_pos
;
1531 buffer_end
= BUFFER_END();
1534 #ifdef HAVE_LCD_BITMAP
1535 static void init_need_scrollbar(void) {
1536 /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
1537 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
1539 prefs
.need_scrollbar
= NEED_SCROLLBAR();
1540 draw_columns
= prefs
.need_scrollbar
? display_columns
-SCROLLBAR_WIDTH
: display_columns
;
1541 par_indent_spaces
= draw_columns
/(5*glyph_width(' '));
1545 static void init_header_and_footer(void)
1549 if (rb
->global_settings
->statusbar
== STATUSBAR_TOP
)
1551 if (prefs
.header_mode
== HD_SBAR
|| prefs
.header_mode
== HD_BOTH
)
1552 header_height
= STATUSBAR_HEIGHT
;
1554 if (prefs
.footer_mode
== FT_SBAR
)
1555 prefs
.footer_mode
= FT_NONE
;
1556 else if (prefs
.footer_mode
== FT_BOTH
)
1557 prefs
.footer_mode
= FT_PAGE
;
1559 else if (rb
->global_settings
->statusbar
== STATUSBAR_BOTTOM
)
1561 if (prefs
.footer_mode
== FT_SBAR
|| prefs
.footer_mode
== FT_BOTH
)
1562 footer_height
= STATUSBAR_HEIGHT
;
1564 if (prefs
.header_mode
== HD_SBAR
)
1565 prefs
.header_mode
= HD_NONE
;
1566 else if (prefs
.header_mode
== HD_BOTH
)
1567 prefs
.header_mode
= HD_PATH
;
1569 else /* STATUSBAR_OFF || STATUSBAR_CUSTOM */
1571 if (prefs
.header_mode
== HD_SBAR
)
1572 prefs
.header_mode
= HD_NONE
;
1573 else if (prefs
.header_mode
== HD_BOTH
)
1574 prefs
.header_mode
= HD_PATH
;
1576 if (prefs
.footer_mode
== FT_SBAR
)
1577 prefs
.footer_mode
= FT_NONE
;
1578 else if (prefs
.footer_mode
== FT_BOTH
)
1579 prefs
.footer_mode
= FT_PAGE
;
1582 if (prefs
.header_mode
== HD_NONE
|| prefs
.header_mode
== HD_PATH
||
1583 prefs
.footer_mode
== FT_NONE
|| prefs
.footer_mode
== FT_PAGE
)
1584 rb
->gui_syncstatusbar_draw(rb
->statusbars
, false);
1586 if (prefs
.header_mode
== HD_PATH
|| prefs
.header_mode
== HD_BOTH
)
1587 header_height
+= pf
->height
;
1588 if (prefs
.footer_mode
== FT_PAGE
|| prefs
.footer_mode
== FT_BOTH
)
1589 footer_height
+= pf
->height
;
1591 display_lines
= (LCD_HEIGHT
- header_height
- footer_height
) / pf
->height
;
1595 last_screen_top_ptr
= NULL
;
1598 static void change_font(unsigned char *font
)
1600 unsigned char buf
[MAX_PATH
];
1602 if (font
== NULL
|| *font
== '\0')
1605 rb
->snprintf(buf
, MAX_PATH
, "%s/%s.fnt", FONT_DIR
, font
);
1606 if (rb
->font_load(NULL
, buf
) < 0)
1607 rb
->splash(HZ
/2, "font load failed.");
1611 static bool viewer_init(void)
1613 #ifdef HAVE_LCD_BITMAP
1614 /* initialize fonts */
1615 pf
= rb
->font_get(FONT_UI
);
1616 draw_columns
= display_columns
= LCD_WIDTH
;
1618 /* REAL fixed pitch :) all chars use up 1 cell */
1620 draw_columns
= display_columns
= 11;
1621 par_indent_spaces
= 2;
1624 fd
= rb
->open(file_name
, O_RDONLY
);
1628 /* Init mac_text value used in processing buffer */
1634 /* When a file is UTF-8 file with BOM, if prefs.encoding is UTF-8,
1635 * then file size decreases only BOM_SIZE.
1637 static void get_filesize(void)
1639 file_size
= rb
->filesize(fd
);
1640 if (file_size
== -1)
1643 if (prefs
.encoding
== UTF_8
&& is_bom
)
1644 file_size
-= BOM_SIZE
;
1647 static int bm_comp(const void *a
, const void *b
)
1649 struct bookmark_info
*pa
;
1650 struct bookmark_info
*pb
;
1652 pa
= (struct bookmark_info
*)a
;
1653 pb
= (struct bookmark_info
*)b
;
1655 if (pa
->page
!= pb
->page
)
1656 return pa
->page
- pb
->page
;
1658 return pa
->line
- pb
->line
;
1661 static void viewer_add_bookmark(void)
1663 if (bookmark_count
>= MAX_BOOKMARKS
-1)
1666 bookmarks
[bookmark_count
].file_position
1667 = file_pos
+ screen_top_ptr
- buffer
;
1668 bookmarks
[bookmark_count
].page
= cpage
;
1669 bookmarks
[bookmark_count
].line
= cline
;
1670 bookmarks
[bookmark_count
].flag
= BOOKMARK_USER
;
1674 static int viewer_add_last_read_bookmark(void)
1678 i
= viewer_find_bookmark(cpage
, cline
);
1680 bookmarks
[i
].flag
|= BOOKMARK_LAST
;
1683 viewer_add_bookmark();
1684 i
= bookmark_count
-1;
1685 bookmarks
[i
].flag
= BOOKMARK_LAST
;
1690 static void viewer_remove_bookmark(int i
)
1694 if (i
< 0 || i
>= bookmark_count
)
1697 for (j
= i
+1; j
< bookmark_count
; j
++)
1698 rb
->memcpy(&bookmarks
[j
-1], &bookmarks
[j
],
1699 sizeof(struct bookmark_info
));
1704 static void viewer_remove_last_read_bookmark(void)
1708 for (i
= 0; i
< bookmark_count
; i
++)
1710 if (bookmarks
[i
].flag
& BOOKMARK_LAST
)
1712 if (bookmarks
[i
].flag
== BOOKMARK_LAST
)
1714 for (j
= i
+1; j
< bookmark_count
; j
++)
1715 rb
->memcpy(&bookmarks
[j
-1], &bookmarks
[j
],
1716 sizeof(struct bookmark_info
));
1721 bookmarks
[i
].flag
= BOOKMARK_USER
;
1727 static int viewer_get_last_read_bookmark(void)
1731 for (i
= 0; i
< bookmark_count
; i
++)
1733 if (bookmarks
[i
].flag
& BOOKMARK_LAST
)
1739 static void viewer_select_bookmark(int initval
)
1748 struct opt_items items
[bookmark_count
];
1749 unsigned char names
[bookmark_count
][38];
1751 if (initval
>= 0 && initval
< bookmark_count
)
1753 ipage
= bookmarks
[initval
].page
;
1754 iline
= bookmarks
[initval
].line
;
1757 rb
->qsort(bookmarks
, bookmark_count
, sizeof(struct bookmark_info
),
1760 for (i
= 0; i
< bookmark_count
; i
++)
1762 rb
->snprintf(names
[i
], sizeof(names
[0]),
1763 #if CONFIG_KEYPAD != PLAYER_PAD
1764 "%sPage: %d Line: %d",
1768 (bookmarks
[i
].flag
&BOOKMARK_LAST
)? "*":" ",
1771 items
[i
].string
= names
[i
];
1772 items
[i
].voice_id
= -1;
1773 if (selected
< 0 && bookmarks
[i
].page
== ipage
&& bookmarks
[i
].line
== iline
)
1777 rb
->set_option("Select bookmark", &selected
, INT
, items
,
1778 sizeof(items
) / sizeof(items
[0]), NULL
);
1780 if (selected
< 0 || selected
>= bookmark_count
)
1782 if (initval
< 0 || (selected
= viewer_get_last_read_bookmark()) < 0)
1785 rb
->splash(HZ
, "Start the first page.");
1787 screen_top_ptr
= buffer
;
1790 buffer_end
= BUFFER_END();
1795 screen_pos
= bookmarks
[selected
].file_position
;
1796 screen_top
= screen_pos
% buffer_size
;
1797 file_pos
= screen_pos
- screen_top
;
1798 screen_top_ptr
= buffer
+ screen_top
;
1799 cpage
= bookmarks
[selected
].page
;
1800 cline
= bookmarks
[selected
].line
;
1801 buffer_end
= BUFFER_END();
1804 static void viewer_default_preferences(void)
1806 prefs
.word_mode
= WRAP
;
1807 prefs
.line_mode
= NORMAL
;
1808 prefs
.view_mode
= NARROW
;
1809 prefs
.scroll_mode
= PAGE
;
1810 prefs
.page_mode
= NO_OVERLAP
;
1811 prefs
.scrollbar_mode
= SB_OFF
;
1812 rb
->memset(prefs
.font
, 0, MAX_PATH
);
1813 #ifdef HAVE_LCD_BITMAP
1814 prefs
.header_mode
= HD_BOTH
;
1815 prefs
.footer_mode
= FT_BOTH
;
1816 rb
->snprintf(prefs
.font
, MAX_PATH
, "%s", rb
->global_settings
->font_file
);
1818 prefs
.header_mode
= HD_NONE
;
1819 prefs
.footer_mode
= FT_NONE
;
1821 prefs
.autoscroll_speed
= 1;
1822 /* Set codepage to system default */
1823 prefs
.encoding
= rb
->global_settings
->default_codepage
;
1826 static bool viewer_read_preferences(int pfd
)
1828 unsigned char buf
[PREFERENCES_SIZE
];
1829 unsigned char *p
= buf
;
1831 if (rb
->read(pfd
, buf
, sizeof(buf
)) != sizeof(buf
))
1834 prefs
.word_mode
= *p
++;
1835 prefs
.line_mode
= *p
++;
1836 prefs
.view_mode
= *p
++;
1837 prefs
.encoding
= *p
++;
1838 prefs
.scrollbar_mode
= *p
++;
1839 prefs
.need_scrollbar
= *p
++;
1840 prefs
.page_mode
= *p
++;
1841 prefs
.header_mode
= *p
++;
1842 prefs
.footer_mode
= *p
++;
1843 prefs
.scroll_mode
= *p
++;
1844 prefs
.autoscroll_speed
= *p
++;
1845 rb
->memcpy(prefs
.font
, p
, MAX_PATH
);
1850 static bool viewer_write_preferences(int pfd
)
1852 unsigned char buf
[PREFERENCES_SIZE
];
1853 unsigned char *p
= buf
;
1855 *p
++ = prefs
.word_mode
;
1856 *p
++ = prefs
.line_mode
;
1857 *p
++ = prefs
.view_mode
;
1858 *p
++ = prefs
.encoding
;
1859 *p
++ = prefs
.scrollbar_mode
;
1860 *p
++ = prefs
.need_scrollbar
;
1861 *p
++ = prefs
.page_mode
;
1862 *p
++ = prefs
.header_mode
;
1863 *p
++ = prefs
.footer_mode
;
1864 *p
++ = prefs
.scroll_mode
;
1865 *p
++ = prefs
.autoscroll_speed
;
1866 rb
->memcpy(p
, prefs
.font
, MAX_PATH
);
1868 return (rb
->write(pfd
, buf
, sizeof(buf
)) == sizeof(buf
));
1871 static bool viewer_read_bookmark_info(int bfd
, struct bookmark_info
*b
)
1873 unsigned char buf
[BOOKMARK_SIZE
];
1875 if (rb
->read(bfd
, buf
, sizeof(buf
)) != sizeof(buf
))
1878 b
->file_position
= (buf
[0] << 24)|(buf
[1] << 16)|(buf
[2] << 8)|buf
[3];
1879 b
->page
= (buf
[4] << 8)|buf
[5];
1886 static bool viewer_read_bookmark_infos(int bfd
)
1891 if (rb
->read(bfd
, &c
, 1) != 1)
1898 if (bookmark_count
> MAX_BOOKMARKS
)
1899 bookmark_count
= MAX_BOOKMARKS
;
1901 for (i
= 0; i
< bookmark_count
; i
++)
1903 if (!viewer_read_bookmark_info(bfd
, &bookmarks
[i
]))
1912 static bool viewer_write_bookmark_info(int bfd
, struct bookmark_info
*b
)
1914 unsigned char buf
[BOOKMARK_SIZE
];
1915 unsigned char *p
= buf
;
1918 ul
= b
->file_position
;
1931 return (rb
->write(bfd
, buf
, sizeof(buf
)) == sizeof(buf
));
1934 static bool viewer_write_bookmark_infos(int bfd
)
1936 unsigned char c
= bookmark_count
;
1939 if (rb
->write(bfd
, &c
, 1) != 1)
1942 for (i
= 0; i
< bookmark_count
; i
++)
1944 if (!viewer_write_bookmark_info(bfd
, &bookmarks
[i
]))
1951 static bool viewer_load_global_settings(void)
1953 unsigned buf
[GLOBAL_SETTINGS_H_SIZE
];
1954 int sfd
= rb
->open(GLOBAL_SETTINGS_FILE
, O_RDONLY
);
1959 if ((rb
->read(sfd
, buf
, GLOBAL_SETTINGS_H_SIZE
) != GLOBAL_SETTINGS_H_SIZE
) ||
1960 rb
->memcmp(buf
, GLOBAL_SETTINGS_HEADER
, GLOBAL_SETTINGS_H_SIZE
) ||
1961 !viewer_read_preferences(sfd
))
1970 static bool viewer_save_global_settings(void)
1972 int sfd
= rb
->open(GLOBAL_SETTINGS_TMP_FILE
, O_WRONLY
|O_CREAT
|O_TRUNC
);
1977 if (rb
->write(sfd
, &GLOBAL_SETTINGS_HEADER
, GLOBAL_SETTINGS_H_SIZE
)
1978 != GLOBAL_SETTINGS_H_SIZE
||
1979 !viewer_write_preferences(sfd
))
1982 rb
->remove(GLOBAL_SETTINGS_TMP_FILE
);
1986 rb
->remove(GLOBAL_SETTINGS_FILE
);
1987 rb
->rename(GLOBAL_SETTINGS_TMP_FILE
, GLOBAL_SETTINGS_FILE
);
1991 static void viewer_load_settings(void)
1993 unsigned char buf
[MAX_PATH
+2];
1994 unsigned int fcount
;
2000 sfd
= rb
->open(SETTINGS_FILE
, O_RDONLY
);
2004 if ((rb
->read(sfd
, buf
, SETTINGS_H_SIZE
+2) != SETTINGS_H_SIZE
+2) ||
2005 rb
->memcmp(buf
, SETTINGS_HEADER
, SETTINGS_H_SIZE
))
2007 /* illegal setting file */
2010 if (rb
->file_exists(SETTINGS_FILE
))
2011 rb
->remove(SETTINGS_FILE
);
2016 fcount
= (buf
[SETTINGS_H_SIZE
] << 8) | buf
[SETTINGS_H_SIZE
+1];
2017 for (i
= 0; i
< fcount
; i
++)
2019 if (rb
->read(sfd
, buf
, MAX_PATH
+2) != MAX_PATH
+2)
2022 size
= (buf
[MAX_PATH
] << 8) | buf
[MAX_PATH
+1];
2023 if (rb
->strcmp(buf
, file_name
))
2025 if (rb
->lseek(sfd
, size
, SEEK_CUR
) < 0)
2029 if (!viewer_read_preferences(sfd
))
2032 res
= viewer_read_bookmark_infos(sfd
);
2041 /* load global settings */
2042 if (!viewer_load_global_settings())
2043 viewer_default_preferences();
2046 screen_top_ptr
= buffer
;
2052 rb
->memcpy(&old_prefs
, &prefs
, sizeof(struct preferences
));
2055 if (bookmark_count
> 1)
2056 viewer_select_bookmark(-1);
2057 else if (bookmark_count
== 1)
2062 screen_pos
= bookmarks
[0].file_position
;
2063 screen_top
= screen_pos
% buffer_size
;
2064 file_pos
= screen_pos
- screen_top
;
2065 screen_top_ptr
= buffer
+ screen_top
;
2066 cpage
= bookmarks
[0].page
;
2067 cline
= bookmarks
[0].line
;
2070 viewer_remove_last_read_bookmark();
2075 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
2077 if (BUFFER_OOB(screen_top_ptr
))
2078 screen_top_ptr
= buffer
;
2080 fill_buffer(file_pos
, buffer
, buffer_size
);
2081 if (prefs
.scroll_mode
== PAGE
&& cline
> 1)
2082 viewer_scroll_to_top_line();
2084 /* remember the current position */
2085 start_position
= file_pos
+ screen_top_ptr
- buffer
;
2087 #ifdef HAVE_LCD_BITMAP
2088 if (rb
->strcmp(prefs
.font
, rb
->global_settings
->font_file
))
2089 change_font(prefs
.font
);
2091 init_need_scrollbar();
2092 init_header_and_footer();
2096 static bool copy_bookmark_file(int sfd
, int dfd
, off_t start
, off_t size
)
2100 if (rb
->lseek(sfd
, start
, SEEK_SET
) < 0)
2105 if (size
> buffer_size
)
2106 rsize
= buffer_size
;
2111 if (rb
->read(sfd
, buffer
, rsize
) != rsize
||
2112 rb
->write(dfd
, buffer
, rsize
) != rsize
)
2118 static bool viewer_save_settings(void)
2120 unsigned char buf
[MAX_PATH
+2];
2121 unsigned int fcount
= 0;
2126 off_t first_copy_size
= 0;
2127 off_t second_copy_start_pos
= 0;
2130 /* add reading page to bookmarks */
2131 idx
= viewer_find_bookmark(cpage
, cline
);
2133 bookmarks
[idx
].flag
|= BOOKMARK_LAST
;
2136 viewer_add_bookmark();
2137 bookmarks
[bookmark_count
-1].flag
= BOOKMARK_LAST
;
2140 tfd
= rb
->open(SETTINGS_TMP_FILE
, O_WRONLY
|O_CREAT
|O_TRUNC
);
2144 ofd
= rb
->open(SETTINGS_FILE
, O_RDWR
);
2147 if ((rb
->read(ofd
, buf
, SETTINGS_H_SIZE
+2) != SETTINGS_H_SIZE
+2) ||
2148 rb
->memcmp(buf
, SETTINGS_HEADER
, SETTINGS_H_SIZE
))
2153 fcount
= (buf
[SETTINGS_H_SIZE
] << 8) | buf
[SETTINGS_H_SIZE
+1];
2155 for (i
= 0; i
< fcount
; i
++)
2157 if (rb
->read(ofd
, buf
, MAX_PATH
+2) != MAX_PATH
+2)
2162 size
= (buf
[MAX_PATH
] << 8) | buf
[MAX_PATH
+1];
2163 if (rb
->strcmp(buf
, file_name
))
2165 if (rb
->lseek(ofd
, size
, SEEK_CUR
) < 0)
2173 first_copy_size
= rb
->lseek(ofd
, 0, SEEK_CUR
);
2174 if (first_copy_size
< 0)
2179 second_copy_start_pos
= first_copy_size
+ size
;
2180 first_copy_size
-= MAX_PATH
+2;
2185 if (first_copy_size
== 0)
2186 first_copy_size
= rb
->filesize(ofd
);
2188 if (!copy_bookmark_file(ofd
, tfd
, 0, first_copy_size
))
2193 if (second_copy_start_pos
> 0)
2195 if (!copy_bookmark_file(ofd
, tfd
, second_copy_start_pos
,
2196 rb
->filesize(ofd
) - second_copy_start_pos
))
2206 rb
->memcpy(buf
, SETTINGS_HEADER
, SETTINGS_H_SIZE
);
2207 buf
[SETTINGS_H_SIZE
] = 0;
2208 buf
[SETTINGS_H_SIZE
+1] = 0;
2209 if (rb
->write(tfd
, buf
, SETTINGS_H_SIZE
+2) != SETTINGS_H_SIZE
+2)
2213 /* copy to current read file's bookmarks */
2214 rb
->memset(buf
, 0, MAX_PATH
);
2215 rb
->snprintf(buf
, MAX_PATH
, "%s", file_name
);
2217 size
= PREFERENCES_SIZE
+ bookmark_count
* BOOKMARK_SIZE
+ 1;
2218 buf
[MAX_PATH
] = size
>> 8;
2219 buf
[MAX_PATH
+1] = size
;
2221 if (rb
->write(tfd
, buf
, MAX_PATH
+2) != MAX_PATH
+2)
2224 if (!viewer_write_preferences(tfd
))
2227 if (!viewer_write_bookmark_infos(tfd
))
2230 if (rb
->lseek(tfd
, SETTINGS_H_SIZE
, SEEK_SET
) < 0)
2234 buf
[0] = fcount
>> 8;
2237 if (rb
->write(tfd
, buf
, 2) != 2)
2242 rb
->remove(SETTINGS_FILE
);
2243 rb
->rename(SETTINGS_TMP_FILE
, SETTINGS_FILE
);
2249 rb
->remove(SETTINGS_TMP_FILE
);
2253 static void viewer_exit(void *parameter
)
2257 /* save preference and bookmarks */
2258 if (!viewer_save_settings())
2259 rb
->splash(HZ
, "Can't save preference and bookmarks.");
2262 #ifdef HAVE_LCD_BITMAP
2263 if (rb
->strcmp(prefs
.font
, rb
->global_settings
->font_file
))
2264 change_font(rb
->global_settings
->font_file
);
2268 static void calc_page(void)
2271 unsigned char *line_begin
;
2272 unsigned char *line_end
;
2274 unsigned char *sstp
;
2276 rb
->splash(0, "Calculating page/line number...");
2278 /* add reading page to bookmarks */
2279 viewer_add_last_read_bookmark();
2281 rb
->qsort(bookmarks
, bookmark_count
, sizeof(struct bookmark_info
),
2287 screen_top_ptr
= buffer
;
2288 buffer_end
= BUFFER_END();
2290 fill_buffer(file_pos
, buffer
, buffer_size
);
2291 line_end
= line_begin
= buffer
;
2293 for (i
= 0; i
< bookmark_count
; i
++)
2295 sfp
= bookmarks
[i
].file_position
;
2298 while ((line_begin
> sstp
|| sstp
>= line_end
) ||
2299 (file_pos
> sfp
|| sfp
>= file_pos
+ BUFFER_END() - buffer
))
2301 get_next_line_position(&line_begin
, &line_end
, NULL
);
2302 if (line_end
== NULL
)
2305 next_line_ptr
= line_end
;
2307 if (sstp
== buffer
&&
2308 file_pos
<= sfp
&& sfp
< file_pos
+ BUFFER_END() - buffer
)
2309 sstp
= sfp
- file_pos
+ buffer
;
2311 increment_current_line();
2314 decrement_current_line();
2315 bookmarks
[i
].page
= cpage
;
2316 bookmarks
[i
].line
= cline
;
2317 bookmarks
[i
].file_position
= file_pos
+ (line_begin
- buffer
);
2318 increment_current_line();
2321 /* remove reading page's bookmark */
2322 for (i
= 0; i
< bookmark_count
; i
++)
2324 if (bookmarks
[i
].flag
& BOOKMARK_LAST
)
2329 screen_pos
= bookmarks
[i
].file_position
;
2330 screen_top
= screen_pos
% buffer_size
;
2331 file_pos
= screen_pos
- screen_top
;
2332 screen_top_ptr
= buffer
+ screen_top
;
2334 cpage
= bookmarks
[i
].page
;
2335 cline
= bookmarks
[i
].line
;
2336 bookmarks
[i
].flag
^= BOOKMARK_LAST
;
2337 buffer_end
= BUFFER_END();
2339 fill_buffer(file_pos
, buffer
, buffer_size
);
2341 if (bookmarks
[i
].flag
== 0)
2342 viewer_remove_bookmark(i
);
2344 if (prefs
.scroll_mode
== PAGE
&& cline
> 1)
2345 viewer_scroll_to_top_line();
2351 static int col_limit(int col
)
2356 if (col
>= max_width
)
2357 col
= max_width
- draw_columns
;
2362 /* settings helper functions */
2364 static bool encoding_setting(void)
2366 static struct opt_items names
[NUM_CODEPAGES
];
2369 enum codepages oldenc
= prefs
.encoding
;
2371 for (idx
= 0; idx
< NUM_CODEPAGES
; idx
++)
2373 names
[idx
].string
= rb
->get_codepage_name(idx
);
2374 names
[idx
].voice_id
= -1;
2377 res
= rb
->set_option("Encoding", &prefs
.encoding
, INT
, names
,
2378 sizeof(names
) / sizeof(names
[0]), NULL
);
2380 /* When prefs.encoding changes into UTF-8 or changes from UTF-8,
2381 * filesize (file_size) might change.
2382 * In addition, if prefs.encoding is UTF-8, then BOM does not read.
2384 if (oldenc
!= prefs
.encoding
&& (oldenc
== UTF_8
|| prefs
.encoding
== UTF_8
))
2388 fill_buffer(file_pos
, buffer
, buffer_size
);
2394 static bool word_wrap_setting(void)
2396 static const struct opt_items names
[] = {
2398 {"Off (Chop Words)", -1},
2401 return rb
->set_option("Word Wrap", &prefs
.word_mode
, INT
,
2405 static bool line_mode_setting(void)
2407 static const struct opt_items names
[] = {
2410 {"Expand Lines", -1},
2411 #ifdef HAVE_LCD_BITMAP
2412 {"Reflow Lines", -1},
2416 return rb
->set_option("Line Mode", &prefs
.line_mode
, INT
, names
,
2417 sizeof(names
) / sizeof(names
[0]), NULL
);
2420 static bool view_mode_setting(void)
2422 static const struct opt_items names
[] = {
2423 {"No (Narrow)", -1},
2427 ret
= rb
->set_option("Wide View", &prefs
.view_mode
, INT
,
2429 if (prefs
.view_mode
== NARROW
)
2435 static bool scroll_mode_setting(void)
2437 static const struct opt_items names
[] = {
2438 {"Scroll by Page", -1},
2439 {"Scroll by Line", -1},
2442 return rb
->set_option("Scroll Mode", &prefs
.scroll_mode
, INT
,
2446 #ifdef HAVE_LCD_BITMAP
2447 static bool page_mode_setting(void)
2449 static const struct opt_items names
[] = {
2454 return rb
->set_option("Overlap Pages", &prefs
.page_mode
, INT
,
2458 static bool scrollbar_setting(void)
2460 static const struct opt_items names
[] = {
2465 return rb
->set_option("Show Scrollbar", &prefs
.scrollbar_mode
, INT
,
2469 static bool header_setting(void)
2471 int len
= (rb
->global_settings
->statusbar
== STATUSBAR_TOP
)? 4 : 2;
2472 struct opt_items names
[len
];
2474 names
[0].string
= "None";
2475 names
[0].voice_id
= -1;
2476 names
[1].string
= "File path";
2477 names
[1].voice_id
= -1;
2479 if (rb
->global_settings
->statusbar
== STATUSBAR_TOP
)
2481 names
[2].string
= "Status bar";
2482 names
[2].voice_id
= -1;
2483 names
[3].string
= "Both";
2484 names
[3].voice_id
= -1;
2487 return rb
->set_option("Show Header", &prefs
.header_mode
, INT
,
2491 static bool footer_setting(void)
2493 int len
= (rb
->global_settings
->statusbar
== STATUSBAR_BOTTOM
)? 4 : 2;
2494 struct opt_items names
[len
];
2496 names
[0].string
= "None";
2497 names
[0].voice_id
= -1;
2498 names
[1].string
= "Page Num";
2499 names
[1].voice_id
= -1;
2501 if (rb
->global_settings
->statusbar
== STATUSBAR_BOTTOM
)
2503 names
[2].string
= "Status bar";
2504 names
[2].voice_id
= -1;
2505 names
[3].string
= "Both";
2506 names
[3].voice_id
= -1;
2509 return rb
->set_option("Show Footer", &prefs
.footer_mode
, INT
,
2513 static int font_comp(const void *a
, const void *b
)
2515 struct opt_items
*pa
;
2516 struct opt_items
*pb
;
2518 pa
= (struct opt_items
*)a
;
2519 pb
= (struct opt_items
*)b
;
2521 return rb
->strcmp(pa
->string
, pb
->string
);
2524 static bool font_setting(void)
2528 struct dirent
*entry
;
2536 dir
= rb
->opendir(FONT_DIR
);
2539 rb
->splash(HZ
/2, "font dir does not access.");
2545 entry
= rb
->readdir(dir
);
2550 len
= rb
->strlen(entry
->d_name
);
2551 if (len
< 4 || rb
->strcmp(entry
->d_name
+ len
-4, ".fnt"))
2558 struct opt_items names
[count
];
2559 unsigned char font_names
[size
];
2560 unsigned char *p
= font_names
;
2562 dir
= rb
->opendir(FONT_DIR
);
2565 rb
->splash(HZ
/2, "font dir does not access.");
2571 entry
= rb
->readdir(dir
);
2576 len
= rb
->strlen(entry
->d_name
);
2577 if (len
< 4 || rb
->strcmp(entry
->d_name
+ len
-4, ".fnt"))
2580 rb
->snprintf(p
, len
-3, "%s", entry
->d_name
);
2581 names
[i
].string
= p
;
2582 names
[i
].voice_id
= -1;
2590 rb
->qsort(names
, count
, sizeof(struct opt_items
), font_comp
);
2592 for (i
= 0; i
< count
; i
++)
2594 if (!rb
->strcmp(names
[i
].string
, prefs
.font
))
2600 old_font
= new_font
;
2602 res
= rb
->set_option("Select Font", &new_font
, INT
,
2603 names
, count
, NULL
);
2605 if (new_font
!= old_font
)
2607 rb
->memset(prefs
.font
, 0, MAX_PATH
);
2608 rb
->snprintf(prefs
.font
, MAX_PATH
, "%s", names
[new_font
].string
);
2609 change_font(prefs
.font
);
2616 static bool autoscroll_speed_setting(void)
2618 return rb
->set_int("Auto-scroll Speed", "", UNIT_INT
,
2619 &prefs
.autoscroll_speed
, NULL
, 1, 1, 10, NULL
);
2622 MENUITEM_FUNCTION(encoding_item
, 0, "Encoding", encoding_setting
,
2623 NULL
, NULL
, Icon_NOICON
);
2624 MENUITEM_FUNCTION(word_wrap_item
, 0, "Word Wrap", word_wrap_setting
,
2625 NULL
, NULL
, Icon_NOICON
);
2626 MENUITEM_FUNCTION(line_mode_item
, 0, "Line Mode", line_mode_setting
,
2627 NULL
, NULL
, Icon_NOICON
);
2628 MENUITEM_FUNCTION(view_mode_item
, 0, "Wide View", view_mode_setting
,
2629 NULL
, NULL
, Icon_NOICON
);
2630 #ifdef HAVE_LCD_BITMAP
2631 MENUITEM_FUNCTION(scrollbar_item
, 0, "Show Scrollbar", scrollbar_setting
,
2632 NULL
, NULL
, Icon_NOICON
);
2633 MENUITEM_FUNCTION(page_mode_item
, 0, "Overlap Pages", page_mode_setting
,
2634 NULL
, NULL
, Icon_NOICON
);
2635 MENUITEM_FUNCTION(header_item
, 0, "Show Header", header_setting
,
2636 NULL
, NULL
, Icon_NOICON
);
2637 MENUITEM_FUNCTION(footer_item
, 0, "Show Footer", footer_setting
,
2638 NULL
, NULL
, Icon_NOICON
);
2639 MENUITEM_FUNCTION(font_item
, 0, "Font", font_setting
,
2640 NULL
, NULL
, Icon_NOICON
);
2642 MENUITEM_FUNCTION(scroll_mode_item
, 0, "Scroll Mode", scroll_mode_setting
,
2643 NULL
, NULL
, Icon_NOICON
);
2644 MENUITEM_FUNCTION(autoscroll_speed_item
, 0, "Auto-Scroll Speed",
2645 autoscroll_speed_setting
, NULL
, NULL
, Icon_NOICON
);
2646 MAKE_MENU(option_menu
, "Viewer Options", NULL
, Icon_NOICON
,
2647 &encoding_item
, &word_wrap_item
, &line_mode_item
, &view_mode_item
,
2648 #ifdef HAVE_LCD_BITMAP
2649 &scrollbar_item
, &page_mode_item
, &header_item
, &footer_item
, &font_item
,
2651 &scroll_mode_item
, &autoscroll_speed_item
);
2653 static bool viewer_options_menu(bool is_global
)
2656 struct preferences tmp_prefs
;
2658 rb
->memcpy(&tmp_prefs
, &prefs
, sizeof(struct preferences
));
2660 result
= (rb
->do_menu(&option_menu
, NULL
, NULL
, false) == MENU_ATTACHED_USB
);
2662 if (!is_global
&& rb
->memcmp(&tmp_prefs
, &prefs
, sizeof(struct preferences
)))
2664 /* Show-scrollbar mode for current view-width mode */
2665 #ifdef HAVE_LCD_BITMAP
2666 init_need_scrollbar();
2667 init_header_and_footer();
2674 static void viewer_menu(void)
2678 MENUITEM_STRINGLIST(menu
, "Viewer Menu", NULL
,
2679 "Return", "Viewer Options",
2680 "Show Playback Menu", "Select Bookmark",
2681 "Global Settings", "Quit");
2683 result
= rb
->do_menu(&menu
, NULL
, NULL
, false);
2686 case 0: /* return */
2688 case 1: /* change settings */
2689 done
= viewer_options_menu(false);
2691 case 2: /* playback control */
2692 playback_control(NULL
);
2694 case 3: /* select bookmark */
2695 viewer_select_bookmark(viewer_add_last_read_bookmark());
2696 viewer_remove_last_read_bookmark();
2697 fill_buffer(file_pos
, buffer
, buffer_size
);
2698 if (prefs
.scroll_mode
== PAGE
&& cline
> 1)
2699 viewer_scroll_to_top_line();
2701 case 4: /* change global settings */
2703 struct preferences orig_prefs
;
2705 rb
->memcpy(&orig_prefs
, &prefs
, sizeof(struct preferences
));
2706 if (!viewer_load_global_settings())
2707 viewer_default_preferences();
2708 done
= viewer_options_menu(true);
2709 viewer_save_global_settings();
2710 rb
->memcpy(&prefs
, &orig_prefs
, sizeof(struct preferences
));
2721 enum plugin_status
plugin_start(const void* file
)
2724 int lastbutton
= BUTTON_NONE
;
2725 bool autoscroll
= false;
2728 old_tick
= *rb
->current_tick
;
2730 /* get the plugin buffer */
2731 buffer
= rb
->plugin_get_buffer((size_t *)&buffer_size
);
2732 if (buffer_size
== 0)
2734 rb
->splash(HZ
, "buffer does not allocate !!");
2735 return PLUGIN_ERROR
;
2737 block_size
= buffer_size
/ 3;
2738 buffer_size
= 3 * block_size
;
2741 return PLUGIN_ERROR
;
2746 rb
->splash(HZ
, "Error opening file.");
2747 return PLUGIN_ERROR
;
2750 viewer_load_settings(); /* load the preferences and bookmark */
2753 rb
->lcd_set_backdrop(NULL
);
2762 if(old_tick
<= *rb
->current_tick
- (110-prefs
.autoscroll_speed
*10))
2764 viewer_scroll_down(true);
2766 old_tick
= *rb
->current_tick
;
2770 button
= rb
->button_get_w_tmo(HZ
/10);
2780 case VIEWER_AUTOSCROLL
:
2781 #ifdef VIEWER_AUTOSCROLL_PRE
2782 if (lastbutton
!= VIEWER_AUTOSCROLL_PRE
)
2785 autoscroll
= !autoscroll
;
2788 case VIEWER_PAGE_UP
:
2789 case VIEWER_PAGE_UP
| BUTTON_REPEAT
:
2790 #ifdef VIEWER_PAGE_UP2
2791 case VIEWER_PAGE_UP2
:
2792 case VIEWER_PAGE_UP2
| BUTTON_REPEAT
:
2794 if (prefs
.scroll_mode
== PAGE
)
2797 #ifdef HAVE_LCD_BITMAP
2798 for (i
= prefs
.page_mode
==OVERLAP
? 1:0; i
< display_lines
; i
++)
2800 for (i
= 0; i
< display_lines
; i
++)
2806 old_tick
= *rb
->current_tick
;
2810 case VIEWER_PAGE_DOWN
:
2811 case VIEWER_PAGE_DOWN
| BUTTON_REPEAT
:
2812 #ifdef VIEWER_PAGE_DOWN2
2813 case VIEWER_PAGE_DOWN2
:
2814 case VIEWER_PAGE_DOWN2
| BUTTON_REPEAT
:
2816 if (prefs
.scroll_mode
== PAGE
)
2819 if (next_screen_ptr
!= NULL
)
2821 screen_top_ptr
= next_screen_to_draw_ptr
;
2822 if (cpage
< MAX_PAGE
)
2827 viewer_scroll_down(autoscroll
);
2828 old_tick
= *rb
->current_tick
;
2832 case VIEWER_SCREEN_LEFT
:
2833 case VIEWER_SCREEN_LEFT
| BUTTON_REPEAT
:
2834 if (prefs
.view_mode
== WIDE
) {
2836 col
-= draw_columns
;
2837 col
= col_limit(col
);
2839 else { /* prefs.view_mode == NARROW */
2847 case VIEWER_SCREEN_RIGHT
:
2848 case VIEWER_SCREEN_RIGHT
| BUTTON_REPEAT
:
2849 if (prefs
.view_mode
== WIDE
) {
2851 col
+= draw_columns
;
2852 col
= col_limit(col
);
2854 else { /* prefs.view_mode == NARROW */
2855 /* Bottom of file */
2862 #ifdef VIEWER_LINE_UP
2863 case VIEWER_LINE_UP
:
2864 case VIEWER_LINE_UP
| BUTTON_REPEAT
:
2865 /* Scroll up one line */
2867 old_tick
= *rb
->current_tick
;
2871 case VIEWER_LINE_DOWN
:
2872 case VIEWER_LINE_DOWN
| BUTTON_REPEAT
:
2873 /* Scroll down one line */
2874 viewer_scroll_down(autoscroll
);
2875 increment_current_line();
2876 old_tick
= *rb
->current_tick
;
2880 #ifdef VIEWER_COLUMN_LEFT
2881 case VIEWER_COLUMN_LEFT
:
2882 case VIEWER_COLUMN_LEFT
| BUTTON_REPEAT
:
2883 if (prefs
.view_mode
== WIDE
) {
2884 /* Scroll left one column */
2885 col
-= glyph_width('o');
2886 col
= col_limit(col
);
2891 case VIEWER_COLUMN_RIGHT
:
2892 case VIEWER_COLUMN_RIGHT
| BUTTON_REPEAT
:
2893 if (prefs
.view_mode
== WIDE
) {
2894 /* Scroll right one column */
2895 col
+= glyph_width('o');
2896 col
= col_limit(col
);
2902 #ifdef VIEWER_RC_QUIT
2903 case VIEWER_RC_QUIT
:
2913 case VIEWER_BOOKMARK
:
2915 int idx
= viewer_find_bookmark(cpage
, cline
);
2919 if (bookmark_count
>= MAX_BOOKMARKS
-1)
2920 rb
->splash(HZ
/2, "No more add bookmark.");
2923 viewer_add_bookmark();
2924 rb
->splash(HZ
/2, "Bookmark add.");
2929 viewer_remove_bookmark(idx
);
2930 rb
->splash(HZ
/2, "Bookmark remove.");
2937 if (rb
->default_event_handler_ex(button
, viewer_exit
, NULL
)
2938 == SYS_USB_CONNECTED
)
2939 return PLUGIN_USB_CONNECTED
;
2942 if (button
!= BUTTON_NONE
)
2944 lastbutton
= button
;