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" /* header="TVGS" */
56 #define GLOBAL_SETTINGS_H_SIZE 5
57 #define GLOBAL_SETTINGS_VERSION 0x32 /* version=2 */
58 #define GLOBAL_SETTINGS_FIRST_VERSION 0x31
60 /* preferences and bookmarks at each file
61 * binary file, so dont use .cfg
66 * --------------------------------
100 #define SETTINGS_FILE VIEWERS_DIR "/viewer_file.dat"
103 #define SETTINGS_TMP_FILE VIEWERS_DIR "/viewer_file.tmp"
105 #define SETTINGS_HEADER "\x54\x56\x53" /* header="TVS" */
106 #define SETTINGS_H_SIZE 4
107 #define SETTINGS_VERSION 0x33 /* version=3 */
108 #define SETTINGS_FIRST_VERSION 0x32
110 #define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */
111 #define NARROW_MAX_COLUMNS 64 /* Max displayable string len [narrow] (over-estimate) */
112 #define WIDE_MAX_COLUMNS 128 /* Max displayable string len [wide] (over-estimate) */
113 #define MAX_WIDTH 910 /* Max line length in WIDE mode */
114 #define READ_PREV_ZONE (block_size*9/10) /* Arbitrary number less than SMALL_BLOCK_SIZE */
115 #define SMALL_BLOCK_SIZE block_size /* Smallest file chunk we will read */
116 #define LARGE_BLOCK_SIZE (block_size << 1) /* Preferable size of file chunk to read */
117 #define TOP_SECTOR buffer
118 #define MID_SECTOR (buffer + SMALL_BLOCK_SIZE)
119 #define BOTTOM_SECTOR (buffer + (SMALL_BLOCK_SIZE << 1))
120 #undef SCROLLBAR_WIDTH
121 #define SCROLLBAR_WIDTH rb->global_settings->scrollbar_width
122 #define MAX_PAGE 9999
124 #define BOOKMARK_SIZE 8
125 #define MAX_BOOKMARKS 10 /* user setting bookmarks + last read page */
127 #define BOOKMARK_LAST 1
128 #define BOOKMARK_USER 2
130 #ifndef HAVE_LCD_BITMAP
131 #define BOOKMARK_ICON "\xee\x84\x81\x00"
134 #define PREFERENCES_SIZE (12 + MAX_PATH)
136 /* Out-Of-Bounds test for any pointer to data in the buffer */
137 #define BUFFER_OOB(p) ((p) < buffer || (p) >= buffer_end)
139 /* Does the buffer contain the beginning of the file? */
140 #define BUFFER_BOF() (file_pos==0)
142 /* Does the buffer contain the end of the file? */
143 #define BUFFER_EOF() (file_size-file_pos <= buffer_size)
145 /* Formula for the endpoint address outside of buffer data */
146 #define BUFFER_END() \
147 ((BUFFER_EOF()) ? (file_size-file_pos+buffer) : (buffer+buffer_size))
149 /* Is the entire file being shown in one screen? */
150 #define ONE_SCREEN_FITS_ALL() \
151 (next_screen_ptr==NULL && screen_top_ptr==buffer && BUFFER_BOF())
153 /* Is a scrollbar called for on the current screen? */
154 #define NEED_SCROLLBAR() \
155 ((!(ONE_SCREEN_FITS_ALL())) && (prefs.scrollbar_mode==SB_ON))
157 /* variable button definitions */
160 #if CONFIG_KEYPAD == RECORDER_PAD
161 #define VIEWER_QUIT BUTTON_OFF
162 #define VIEWER_PAGE_UP BUTTON_UP
163 #define VIEWER_PAGE_DOWN BUTTON_DOWN
164 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
165 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
166 #define VIEWER_MENU BUTTON_F1
167 #define VIEWER_AUTOSCROLL BUTTON_PLAY
168 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
169 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
170 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
171 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
172 #define VIEWER_BOOKMARK BUTTON_F2
174 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
175 #define VIEWER_QUIT BUTTON_OFF
176 #define VIEWER_PAGE_UP BUTTON_UP
177 #define VIEWER_PAGE_DOWN BUTTON_DOWN
178 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
179 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
180 #define VIEWER_MENU BUTTON_F1
181 #define VIEWER_AUTOSCROLL BUTTON_SELECT
182 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
183 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
184 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
185 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
186 #define VIEWER_BOOKMARK BUTTON_F2
189 #elif CONFIG_KEYPAD == ONDIO_PAD
190 #define VIEWER_QUIT BUTTON_OFF
191 #define VIEWER_PAGE_UP BUTTON_UP
192 #define VIEWER_PAGE_DOWN BUTTON_DOWN
193 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
194 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
195 #define VIEWER_MENU (BUTTON_MENU|BUTTON_REPEAT)
196 #define VIEWER_AUTOSCROLL_PRE BUTTON_MENU
197 #define VIEWER_AUTOSCROLL (BUTTON_MENU|BUTTON_REL)
198 #define VIEWER_BOOKMARK (BUTTON_MENU|BUTTON_OFF)
201 #elif CONFIG_KEYPAD == PLAYER_PAD
202 #define VIEWER_QUIT BUTTON_STOP
203 #define VIEWER_PAGE_UP BUTTON_LEFT
204 #define VIEWER_PAGE_DOWN BUTTON_RIGHT
205 #define VIEWER_SCREEN_LEFT (BUTTON_ON|BUTTON_LEFT)
206 #define VIEWER_SCREEN_RIGHT (BUTTON_ON|BUTTON_RIGHT)
207 #define VIEWER_MENU BUTTON_MENU
208 #define VIEWER_AUTOSCROLL BUTTON_PLAY
209 #define VIEWER_BOOKMARK BUTTON_ON
211 /* iRiver H1x0 && H3x0 keys */
212 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
213 (CONFIG_KEYPAD == IRIVER_H300_PAD)
214 #define VIEWER_QUIT BUTTON_OFF
215 #define VIEWER_PAGE_UP BUTTON_UP
216 #define VIEWER_PAGE_DOWN BUTTON_DOWN
217 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
218 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
219 #define VIEWER_MENU BUTTON_MODE
220 #define VIEWER_AUTOSCROLL BUTTON_SELECT
221 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
222 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
223 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
224 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
225 #define VIEWER_BOOKMARK (BUTTON_ON | BUTTON_SELECT)
227 #define VIEWER_RC_QUIT BUTTON_RC_STOP
230 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
231 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
232 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
233 #define VIEWER_QUIT_PRE BUTTON_SELECT
234 #define VIEWER_QUIT (BUTTON_SELECT | BUTTON_MENU)
235 #define VIEWER_PAGE_UP BUTTON_SCROLL_BACK
236 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_FWD
237 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
238 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
239 #define VIEWER_MENU BUTTON_MENU
240 #define VIEWER_AUTOSCROLL BUTTON_PLAY
241 #define VIEWER_BOOKMARK BUTTON_SELECT
244 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
245 #define VIEWER_QUIT BUTTON_PLAY
246 #define VIEWER_PAGE_UP BUTTON_UP
247 #define VIEWER_PAGE_DOWN BUTTON_DOWN
248 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
249 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
250 #define VIEWER_MENU BUTTON_MODE
251 #define VIEWER_AUTOSCROLL BUTTON_SELECT
252 #define VIEWER_BOOKMARK (BUTTON_LEFT|BUTTON_SELECT)
255 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
256 #define VIEWER_QUIT BUTTON_POWER
257 #define VIEWER_PAGE_UP BUTTON_UP
258 #define VIEWER_PAGE_DOWN BUTTON_DOWN
259 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
260 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
261 #define VIEWER_MENU BUTTON_SELECT
262 #define VIEWER_AUTOSCROLL BUTTON_PLAY
263 #define VIEWER_BOOKMARK BUTTON_REC
266 #elif CONFIG_KEYPAD == GIGABEAT_PAD
267 #define VIEWER_QUIT BUTTON_POWER
268 #define VIEWER_PAGE_UP BUTTON_UP
269 #define VIEWER_PAGE_DOWN BUTTON_DOWN
270 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
271 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
272 #define VIEWER_MENU BUTTON_MENU
273 #define VIEWER_AUTOSCROLL BUTTON_A
274 #define VIEWER_BOOKMARK BUTTON_SELECT
276 /* Sansa E200 keys */
277 #elif CONFIG_KEYPAD == SANSA_E200_PAD
278 #define VIEWER_QUIT BUTTON_POWER
279 #define VIEWER_PAGE_UP BUTTON_UP
280 #define VIEWER_PAGE_DOWN BUTTON_DOWN
281 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
282 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
283 #define VIEWER_MENU BUTTON_SELECT
284 #define VIEWER_AUTOSCROLL BUTTON_REC
285 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
286 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
287 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
289 /* Sansa Fuze keys */
290 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
291 #define VIEWER_QUIT (BUTTON_HOME|BUTTON_REPEAT)
292 #define VIEWER_PAGE_UP BUTTON_UP
293 #define VIEWER_PAGE_DOWN BUTTON_DOWN
294 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
295 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
296 #define VIEWER_MENU BUTTON_SELECT|BUTTON_REPEAT
297 #define VIEWER_AUTOSCROLL BUTTON_SELECT|BUTTON_DOWN
298 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
299 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
300 #define VIEWER_BOOKMARK BUTTON_SELECT
302 /* Sansa C200 keys */
303 #elif CONFIG_KEYPAD == SANSA_C200_PAD
304 #define VIEWER_QUIT BUTTON_POWER
305 #define VIEWER_PAGE_UP BUTTON_VOL_UP
306 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
307 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
308 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
309 #define VIEWER_MENU BUTTON_SELECT
310 #define VIEWER_AUTOSCROLL BUTTON_REC
311 #define VIEWER_LINE_UP BUTTON_UP
312 #define VIEWER_LINE_DOWN BUTTON_DOWN
313 #define VIEWER_BOOKMARK (BUTTON_DOWN | BUTTON_SELECT)
315 /* Sansa Clip keys */
316 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
317 #define VIEWER_QUIT BUTTON_POWER
318 #define VIEWER_PAGE_UP BUTTON_VOL_UP
319 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
320 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
321 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
322 #define VIEWER_MENU BUTTON_SELECT
323 #define VIEWER_AUTOSCROLL BUTTON_HOME
324 #define VIEWER_LINE_UP BUTTON_UP
325 #define VIEWER_LINE_DOWN BUTTON_DOWN
326 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
328 /* Sansa M200 keys */
329 #elif CONFIG_KEYPAD == SANSA_M200_PAD
330 #define VIEWER_QUIT BUTTON_POWER
331 #define VIEWER_PAGE_UP BUTTON_VOL_UP
332 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
333 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
334 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
335 #define VIEWER_MENU (BUTTON_SELECT | BUTTON_UP)
336 #define VIEWER_AUTOSCROLL (BUTTON_SELECT | BUTTON_REL)
337 #define VIEWER_LINE_UP BUTTON_UP
338 #define VIEWER_LINE_DOWN BUTTON_DOWN
339 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
341 /* iriver H10 keys */
342 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
343 #define VIEWER_QUIT BUTTON_POWER
344 #define VIEWER_PAGE_UP BUTTON_SCROLL_UP
345 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_DOWN
346 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
347 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
348 #define VIEWER_MENU BUTTON_REW
349 #define VIEWER_AUTOSCROLL BUTTON_PLAY
350 #define VIEWER_BOOKMARK BUTTON_FF
353 #elif CONFIG_KEYPAD == MROBE500_PAD
354 #define VIEWER_QUIT BUTTON_POWER
355 #define VIEWER_PAGE_UP BUTTON_RC_PLAY
356 #define VIEWER_PAGE_DOWN BUTTON_RC_DOWN
357 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
358 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
359 #define VIEWER_MENU BUTTON_RC_HEART
360 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
361 #define VIEWER_BOOKMARK BUTTON_CENTER
364 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
365 #define VIEWER_QUIT BUTTON_BACK
366 #define VIEWER_PAGE_UP BUTTON_PREV
367 #define VIEWER_PAGE_DOWN BUTTON_NEXT
368 #define VIEWER_SCREEN_LEFT (BUTTON_PLAY | BUTTON_LEFT)
369 #define VIEWER_SCREEN_RIGHT (BUTTON_PLAY | BUTTON_RIGHT)
370 #define VIEWER_MENU BUTTON_MENU
371 #define VIEWER_AUTOSCROLL_PRE BUTTON_PLAY
372 #define VIEWER_AUTOSCROLL (BUTTON_PLAY|BUTTON_REL)
373 #define VIEWER_LINE_UP BUTTON_UP
374 #define VIEWER_LINE_DOWN BUTTON_DOWN
375 #define VIEWER_COLUMN_LEFT BUTTON_LEFT
376 #define VIEWER_COLUMN_RIGHT BUTTON_RIGHT
377 #define VIEWER_BOOKMARK BUTTON_SELECT
380 #elif CONFIG_KEYPAD == MROBE100_PAD
381 #define VIEWER_QUIT BUTTON_POWER
382 #define VIEWER_PAGE_UP BUTTON_UP
383 #define VIEWER_PAGE_DOWN BUTTON_DOWN
384 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
385 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
386 #define VIEWER_MENU BUTTON_MENU
387 #define VIEWER_AUTOSCROLL BUTTON_DISPLAY
388 #define VIEWER_BOOKMARK BUTTON_SELECT
391 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
392 #define VIEWER_QUIT BUTTON_REC
393 #define VIEWER_PAGE_UP BUTTON_RC_VOL_UP
394 #define VIEWER_PAGE_DOWN BUTTON_RC_VOL_DOWN
395 #define VIEWER_SCREEN_LEFT BUTTON_RC_REW
396 #define VIEWER_SCREEN_RIGHT BUTTON_RC_FF
397 #define VIEWER_MENU BUTTON_RC_MENU
398 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
399 #define VIEWER_RC_QUIT BUTTON_RC_REC
400 #define VIEWER_BOOKMARK BUTTON_RC_PLAY
403 #elif CONFIG_KEYPAD == COWON_D2_PAD
404 #define VIEWER_QUIT BUTTON_POWER
405 #define VIEWER_MENU BUTTON_MENU
406 #define VIEWER_PAGE_UP BUTTON_MINUS
407 #define VIEWER_PAGE_DOWN BUTTON_PLUS
408 #define VIEWER_BOOKMARK (BUTTON_MENU|BUTTON_PLUS)
410 #elif CONFIG_KEYPAD == IAUDIO67_PAD
411 #define VIEWER_QUIT BUTTON_POWER
412 #define VIEWER_PAGE_UP BUTTON_VOLUP
413 #define VIEWER_PAGE_DOWN BUTTON_VOLDOWN
414 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
415 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
416 #define VIEWER_MENU BUTTON_MENU
417 #define VIEWER_AUTOSCROLL BUTTON_PLAY
418 #define VIEWER_RC_QUIT BUTTON_STOP
419 #define VIEWER_BOOKMARK (BUTTON_LEFT|BUTTON_PLAY)
421 /* Creative Zen Vision:M keys */
422 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
423 #define VIEWER_QUIT BUTTON_BACK
424 #define VIEWER_PAGE_UP BUTTON_UP
425 #define VIEWER_PAGE_DOWN BUTTON_DOWN
426 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
427 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
428 #define VIEWER_MENU BUTTON_MENU
429 #define VIEWER_AUTOSCROLL BUTTON_SELECT
430 #define VIEWER_BOOKMARK BUTTON_PLAY
432 /* Philips HDD1630 keys */
433 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
434 #define VIEWER_QUIT BUTTON_POWER
435 #define VIEWER_PAGE_UP BUTTON_UP
436 #define VIEWER_PAGE_DOWN BUTTON_DOWN
437 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
438 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
439 #define VIEWER_MENU BUTTON_MENU
440 #define VIEWER_AUTOSCROLL BUTTON_VIEW
441 #define VIEWER_BOOKMARK BUTTON_SELECT
443 /* Philips SA9200 keys */
444 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
445 #define VIEWER_QUIT BUTTON_POWER
446 #define VIEWER_PAGE_UP BUTTON_UP
447 #define VIEWER_PAGE_DOWN BUTTON_DOWN
448 #define VIEWER_SCREEN_LEFT BUTTON_PREV
449 #define VIEWER_SCREEN_RIGHT BUTTON_NEXT
450 #define VIEWER_MENU BUTTON_MENU
451 #define VIEWER_AUTOSCROLL BUTTON_PLAY
452 #define VIEWER_BOOKMARK BUTTON_RIGHT
454 /* Onda VX747 keys */
455 #elif CONFIG_KEYPAD == ONDAVX747_PAD
456 #define VIEWER_QUIT BUTTON_POWER
457 #define VIEWER_MENU BUTTON_MENU
458 #define VIEWER_BOOKMARK (BUTTON_RIGHT|BUTTON_POWER)
460 /* Onda VX777 keys */
461 #elif CONFIG_KEYPAD == ONDAVX777_PAD
462 #define VIEWER_QUIT BUTTON_POWER
463 #define VIEWER_BOOKMARK (BUTTON_RIGHT|BUTTON_POWER)
465 /* SAMSUNG YH-820 / YH-920 / YH-925 keys */
466 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
467 #define VIEWER_QUIT BUTTON_REC
468 #define VIEWER_PAGE_UP BUTTON_UP
469 #define VIEWER_PAGE_DOWN BUTTON_DOWN
470 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
471 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
472 #define VIEWER_MENU BUTTON_PLAY
473 #define VIEWER_AUTOSCROLL BUTTON_REW
474 #define VIEWER_BOOKMARK BUTTON_FFWD
476 /* Packard Bell Vibe 500 keys */
477 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
478 #define VIEWER_QUIT BUTTON_REC
479 #define VIEWER_PAGE_UP BUTTON_OK
480 #define VIEWER_PAGE_DOWN BUTTON_CANCEL
481 #define VIEWER_LINE_UP BUTTON_UP
482 #define VIEWER_LINE_DOWN BUTTON_DOWN
483 #define VIEWER_SCREEN_LEFT BUTTON_PREV
484 #define VIEWER_SCREEN_RIGHT BUTTON_NEXT
485 #define VIEWER_MENU BUTTON_MENU
486 #define VIEWER_AUTOSCROLL BUTTON_PLAY
487 #define VIEWER_BOOKMARK BUTTON_POWER
490 #error No keymap defined!
493 #ifdef HAVE_TOUCHSCREEN
495 #define VIEWER_QUIT2 BUTTON_TOPLEFT
497 #define VIEWER_QUIT BUTTON_TOPLEFT
499 #ifdef VIEWER_PAGE_UP
500 #define VIEWER_PAGE_UP2 BUTTON_TOPMIDDLE
502 #define VIEWER_PAGE_UP BUTTON_TOPMIDDLE
504 #ifdef VIEWER_PAGE_DOWN
505 #define VIEWER_PAGE_DOWN2 BUTTON_BOTTOMMIDDLE
507 #define VIEWER_PAGE_DOWN BUTTON_BOTTOMMIDDLE
509 #ifndef VIEWER_SCREEN_LEFT
510 #define VIEWER_SCREEN_LEFT BUTTON_MIDLEFT
512 #ifndef VIEWER_SCREEN_RIGHT
513 #define VIEWER_SCREEN_RIGHT BUTTON_MIDRIGHT
516 #define VIEWER_MENU2 BUTTON_TOPRIGHT
518 #define VIEWER_MENU BUTTON_TOPRIGHT
520 #ifndef VIEWER_AUTOSCROLL
521 #define VIEWER_AUTOSCROLL BUTTON_CENTER
525 /* stuff for the bookmarking */
526 struct bookmark_info
{
543 REFLOW
, /* won't be set on charcell LCD, must be last */
556 enum codepages encoding
;
588 int autoscroll_speed
;
590 unsigned char font
[MAX_PATH
];
594 VIEWER_FONT_MENU
= 0,
598 struct preferences prefs
;
599 struct preferences old_prefs
;
601 static unsigned char *buffer
;
602 static long buffer_size
;
603 static long block_size
= 0x1000;
604 static unsigned char line_break
[] = {0,0x20,9,0xB,0xC,'-'};
605 static int display_columns
; /* number of (pixel) columns on the display */
606 static int display_lines
; /* number of lines on the display */
607 static int draw_columns
; /* number of (pixel) columns available for text */
608 static int par_indent_spaces
; /* number of spaces to indent first paragraph */
610 static const char *file_name
;
611 static long file_size
;
612 static long start_position
; /* position in the file after the viewer is started */
613 static bool mac_text
;
614 static long file_pos
; /* Position of the top of the buffer in the file */
615 static long last_file_pos
;
616 static unsigned char *buffer_end
; /*Set to BUFFER_END() when file_pos changes*/
617 static int max_line_len
;
618 static int max_width
;
619 static int max_columns
;
620 static int cline
= 1;
621 static int cpage
= 1;
622 static int lpage
= 0;
623 static unsigned char *screen_top_ptr
;
624 static unsigned char *next_screen_ptr
;
625 static unsigned char *next_screen_to_draw_ptr
;
626 static unsigned char *next_line_ptr
;
627 static unsigned char *last_screen_top_ptr
= NULL
;
628 #ifdef HAVE_LCD_BITMAP
629 static struct font
*pf
;
630 static int header_height
= 0;
631 static int footer_height
= 0;
633 struct bookmark_info bookmarks
[MAX_BOOKMARKS
];
634 static int bookmark_count
;
637 #define BOM "\xef\xbb\xbf"
640 static bool is_bom
= false;
642 /* calculate the width of a UCS character (zero width for diacritics) */
643 static int glyph_width(unsigned short ch
)
648 #ifdef HAVE_LCD_BITMAP
649 if (rb
->is_diacritic(ch
, NULL
))
652 return rb
->font_get_width(pf
, ch
);
658 /* get UCS character from string */
659 static unsigned char* get_ucs(const unsigned char* str
, unsigned short* ch
)
661 unsigned char utf8_tmp
[6];
664 if (prefs
.encoding
== UTF_8
)
665 return (unsigned char*)rb
->utf8decode(str
, ch
);
667 count
= BUFFER_OOB(str
+2)? 1:2;
668 rb
->iso_decode(str
, utf8_tmp
, prefs
.encoding
, count
);
669 rb
->utf8decode(utf8_tmp
, ch
);
671 /* return a pointer after the parsed section of the string */
672 #ifdef HAVE_LCD_BITMAP
673 if (prefs
.encoding
>= SJIS
&& *str
>= 0x80
674 && !(prefs
.encoding
== SJIS
&& *str
> 0xA0 && *str
< 0xE0))
675 return (unsigned char*)str
+2;
678 return (unsigned char*)str
+1;
681 /* decode UCS string into UTF-8 string */
682 static unsigned char *decode2utf8(const unsigned char *src
, unsigned char *dst
,
683 int skip_width
, int disp_width
)
686 const unsigned char *oldstr
;
687 const unsigned char *str
= src
;
688 unsigned char *utf8
= dst
;
691 /* skip the skip_width */
695 str
= get_ucs(oldstr
, &ch
);
696 width
+= glyph_width(ch
);
697 if (width
> skip_width
)
704 /* decode until string end or disp_width reached */
708 str
= get_ucs(str
, &ch
);
709 width
+= glyph_width(ch
);
710 if (width
> disp_width
)
713 utf8
= rb
->utf8encode(ch
, utf8
);
716 /* return a pointer after the dst string ends */
720 /* set max_columns and max_width */
721 static void calc_max_width(void)
723 if (prefs
.view_mode
== NARROW
)
725 max_columns
= NARROW_MAX_COLUMNS
;
726 max_width
= draw_columns
;
730 max_columns
= WIDE_MAX_COLUMNS
;
731 max_width
= 2 * draw_columns
;
735 static bool done
= false;
738 static inline void advance_conters(unsigned short ch
, int* k
, int* width
)
740 #ifdef HAVE_LCD_BITMAP
741 /* diacritics do not count */
742 if (rb
->is_diacritic(ch
, NULL
))
746 *width
+= glyph_width(ch
);
750 static inline bool line_is_full(int k
, int width
)
752 return ((k
>= max_columns
- 1) || (width
>= max_width
));
755 static unsigned char* crop_at_width(const unsigned char* p
)
759 const unsigned char *oldp
= p
;
763 while (!line_is_full(k
, width
)) {
768 advance_conters(ch
, &k
, &width
);
771 return (unsigned char*)oldp
;
774 static unsigned char* find_first_feed(const unsigned char* p
, int size
)
778 const unsigned char *oldp
= p
;
783 return (unsigned char*)p
;
792 static unsigned char* find_last_feed(const unsigned char* p
, int size
)
796 for (i
=size
-1; i
>=0; i
--)
798 return (unsigned char*) p
+i
;
803 static unsigned char* find_last_space(const unsigned char* p
, int size
)
807 k
= (prefs
.line_mode
==JOIN
) || (prefs
.line_mode
==REFLOW
) ? 0:1;
810 if (!BUFFER_OOB(&p
[i
]))
811 for (j
=k
; j
< ((int) sizeof(line_break
)) - 1; j
++) {
812 if (p
[i
] == line_break
[j
])
813 return (unsigned char*) p
+i
;
816 if (prefs
.word_mode
== WRAP
) {
817 for (i
=size
-1; i
>=0; i
--) {
818 for (j
=k
; j
< (int) sizeof(line_break
) - 1; j
++) {
819 if (p
[i
] == line_break
[j
])
820 return (unsigned char*) p
+i
;
828 static unsigned char* find_next_line(const unsigned char* cur_line
, bool *is_short
)
830 const unsigned char *next_line
= NULL
;
831 int size
, i
, j
, j_next
, j_prev
, k
, width
, search_len
, spaces
, newlines
;
835 if (is_short
!= NULL
)
838 if BUFFER_OOB(cur_line
)
841 if (prefs
.view_mode
== WIDE
) {
842 search_len
= MAX_WIDTH
;
844 else { /* prefs.view_mode == NARROW */
845 search_len
= crop_at_width(cur_line
) - cur_line
;
848 size
= BUFFER_OOB(cur_line
+search_len
) ? buffer_end
-cur_line
: search_len
;
850 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
)) {
851 /* Need to scan ahead and possibly increase search_len and size,
852 or possibly set next_line at second hard return in a row. */
855 j_next
=j
=k
=width
=spaces
=newlines
=0;
857 const unsigned char *p
, *oldp
;
862 if (BUFFER_OOB(cur_line
+j
))
864 if (line_is_full(k
, width
)) {
865 size
= search_len
= j_prev
;
869 oldp
= p
= &cur_line
[j
];
871 j_next
= j
+ (p
- oldp
);
875 if (prefs
.line_mode
== REFLOW
) {
878 next_line
= cur_line
+ size
;
879 return (unsigned char*) next_line
;
881 if (j
==0) /* i=1 is intentional */
882 for (i
=0; i
<par_indent_spaces
; i
++)
883 advance_conters(' ', &k
, &width
);
885 if (!first_chars
) spaces
++;
891 next_line
= cur_line
+ size
- spaces
;
892 if (next_line
!= cur_line
)
893 return (unsigned char*) next_line
;
899 if (BUFFER_OOB(cur_line
+size
) || size
> 2*search_len
)
902 spaces
= first_chars
? 0:1;
906 if (prefs
.line_mode
==JOIN
|| newlines
>0) {
909 advance_conters(' ', &k
, &width
);
910 if (line_is_full(k
, width
)) {
911 size
= search_len
= j
;
917 /* REFLOW, multiple spaces between words: count only
918 * one. If more are needed, they will be added
922 advance_conters(' ', &k
, &width
);
923 if (line_is_full(k
, width
)) {
924 size
= search_len
= j
;
929 advance_conters(ch
, &k
, &width
);
935 /* find first hard return */
936 next_line
= find_first_feed(cur_line
, size
);
939 if (next_line
== NULL
)
940 if (size
== search_len
) {
941 if (prefs
.word_mode
== WRAP
) /* Find last space */
942 next_line
= find_last_space(cur_line
, size
);
944 if (next_line
== NULL
) {
945 next_line
= crop_at_width(cur_line
);
948 if (prefs
.word_mode
== WRAP
) {
949 for (i
=0;i
<WRAP_TRIM
;i
++) {
950 if (!(isspace(next_line
[0]) && !BUFFER_OOB(next_line
)))
958 if (prefs
.line_mode
== EXPAND
)
959 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
960 if (next_line
[0] == 0)
961 if (next_line
!= cur_line
)
962 return (unsigned char*) next_line
;
964 /* If next_line is pointing to a zero, increment it; i.e.,
965 leave the terminator at the end of cur_line. If pointing
966 to a hyphen, increment only if there is room to display
967 the hyphen on current line (won't apply in WIDE mode,
968 since it's guarenteed there won't be room). */
969 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
970 if (next_line
[0] == 0)/* ||
971 (next_line[0] == '-' && next_line-cur_line < draw_columns)) */
974 if (BUFFER_OOB(next_line
))
976 if (BUFFER_EOF() && next_line
!= cur_line
)
977 return (unsigned char*) next_line
;
984 return (unsigned char*) next_line
;
987 static unsigned char* find_prev_line(const unsigned char* cur_line
)
989 const unsigned char *prev_line
= NULL
;
990 const unsigned char *p
;
992 if BUFFER_OOB(cur_line
)
995 /* To wrap consistently at the same places, we must
996 start with a known hard return, then work downwards.
997 We can either search backwards for a hard return,
998 or simply start wrapping downwards from top of buffer.
999 If current line is not near top of buffer, this is
1000 a file with long lines (paragraphs). We would need to
1001 read earlier sectors before we could decide how to
1002 properly wrap the lines above the current line, but
1003 it probably is not worth the disk access. Instead,
1004 start with top of buffer and wrap down from there.
1005 This may result in some lines wrapping at different
1006 points from where they wrap when scrolling down.
1007 If buffer is at top of file, start at top of buffer. */
1009 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
))
1010 prev_line
= p
= NULL
;
1012 prev_line
= p
= find_last_feed(buffer
, cur_line
-buffer
-1);
1013 /* Null means no line feeds in buffer above current line. */
1015 if (prev_line
== NULL
)
1016 if (BUFFER_BOF() || cur_line
- buffer
> READ_PREV_ZONE
)
1017 prev_line
= p
= buffer
;
1018 /* (else return NULL and read previous block) */
1020 /* Wrap downwards until too far, then use the one before. */
1021 while (p
!= NULL
&& p
< cur_line
) {
1023 p
= find_next_line(prev_line
, NULL
);
1026 if (BUFFER_OOB(prev_line
))
1029 return (unsigned char*) prev_line
;
1032 static void check_bom(void)
1034 unsigned char bom
[BOM_SIZE
];
1035 off_t orig
= rb
->lseek(fd
, 0, SEEK_CUR
);
1039 rb
->lseek(fd
, 0, SEEK_SET
);
1041 if (rb
->read(fd
, bom
, BOM_SIZE
) == BOM_SIZE
)
1042 is_bom
= !memcmp(bom
, BOM
, BOM_SIZE
);
1044 rb
->lseek(fd
, orig
, SEEK_SET
);
1047 static void fill_buffer(long pos
, unsigned char* buf
, unsigned size
)
1049 /* Read from file and preprocess the data */
1050 /* To minimize disk access, always read on sector boundaries */
1051 unsigned numread
, i
;
1052 bool found_CR
= false;
1053 off_t offset
= rb
->lseek(fd
, pos
, SEEK_SET
);
1055 if (offset
== 0 && prefs
.encoding
== UTF_8
&& is_bom
)
1056 rb
->lseek(fd
, BOM_SIZE
, SEEK_SET
);
1058 numread
= rb
->read(fd
, buf
, size
- 1);
1060 rb
->button_clear_queue(); /* clear button queue */
1062 for(i
= 0; i
< numread
; i
++) {
1079 case 0: /* No break between case 0 and default, intentionally */
1092 static int viewer_find_bookmark(int page
, int line
)
1096 for (i
= 0; i
< bookmark_count
; i
++)
1098 if (bookmarks
[i
].page
== page
&& bookmarks
[i
].line
== line
)
1104 static int read_and_synch(int direction
)
1106 /* Read next (or prev) block, and reposition global pointers. */
1107 /* direction: 1 for down (i.e., further into file), -1 for up */
1108 int move_size
, move_vector
, offset
;
1109 unsigned char *fill_buf
;
1111 if (direction
== -1) /* up */ {
1112 move_size
= SMALL_BLOCK_SIZE
;
1114 fill_buf
= TOP_SECTOR
;
1115 rb
->memcpy(BOTTOM_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
1116 rb
->memcpy(MID_SECTOR
, TOP_SECTOR
, SMALL_BLOCK_SIZE
);
1119 if (prefs
.view_mode
== WIDE
) {
1120 /* WIDE mode needs more buffer so we have to read smaller blocks */
1121 move_size
= SMALL_BLOCK_SIZE
;
1122 offset
= LARGE_BLOCK_SIZE
;
1123 fill_buf
= BOTTOM_SECTOR
;
1124 rb
->memcpy(TOP_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
1125 rb
->memcpy(MID_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
1128 move_size
= LARGE_BLOCK_SIZE
;
1129 offset
= SMALL_BLOCK_SIZE
;
1130 fill_buf
= MID_SECTOR
;
1131 rb
->memcpy(TOP_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
1134 move_vector
= direction
* move_size
;
1135 screen_top_ptr
-= move_vector
;
1136 file_pos
+= move_vector
;
1137 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1138 fill_buffer(file_pos
+ offset
, fill_buf
, move_size
);
1142 static void get_next_line_position(unsigned char **line_begin
,
1143 unsigned char **line_end
,
1148 *line_begin
= *line_end
;
1149 *line_end
= find_next_line(*line_begin
, is_short
);
1151 if (*line_end
== NULL
&& !BUFFER_EOF())
1153 resynch_move
= read_and_synch(1); /* Read block & move ptrs */
1154 *line_begin
-= resynch_move
;
1155 if (next_line_ptr
> buffer
)
1156 next_line_ptr
-= resynch_move
;
1158 *line_end
= find_next_line(*line_begin
, is_short
);
1162 static void increment_current_line(void)
1164 if (cline
< display_lines
)
1166 else if (cpage
< MAX_PAGE
)
1173 static void decrement_current_line(void)
1180 cline
= display_lines
;
1184 static void viewer_scroll_up(void)
1188 p
= find_prev_line(screen_top_ptr
);
1189 if (p
== NULL
&& !BUFFER_BOF()) {
1191 p
= find_prev_line(screen_top_ptr
);
1196 decrement_current_line();
1199 static void viewer_scroll_down(bool autoscroll
)
1204 if (next_line_ptr
!= NULL
)
1205 screen_top_ptr
= next_line_ptr
;
1207 if (prefs
.scroll_mode
== LINE
|| autoscroll
)
1208 increment_current_line();
1211 static void viewer_scroll_to_top_line(void)
1215 for (line
= cline
; line
> 1; line
--)
1219 #ifdef HAVE_LCD_BITMAP
1220 static void viewer_scrollbar(void) {
1221 int items
, min_shown
, max_shown
, sb_begin_y
, sb_height
;
1223 items
= (int) file_size
; /* (SH1 int is same as long) */
1224 min_shown
= (int) file_pos
+ (screen_top_ptr
- buffer
);
1226 if (next_screen_ptr
== NULL
)
1229 max_shown
= min_shown
+ (next_screen_ptr
- screen_top_ptr
);
1231 sb_begin_y
= header_height
;
1232 sb_height
= LCD_HEIGHT
- header_height
- footer_height
;
1234 rb
->gui_scrollbar_draw(rb
->screens
[SCREEN_MAIN
],0, sb_begin_y
,
1235 SCROLLBAR_WIDTH
-1, sb_height
,
1236 items
, min_shown
, max_shown
, VERTICAL
);
1240 #ifdef HAVE_LCD_BITMAP
1241 static void viewer_show_header(void)
1243 if (prefs
.header_mode
== HD_SBAR
|| prefs
.header_mode
== HD_BOTH
)
1244 rb
->gui_syncstatusbar_draw(rb
->statusbars
, true);
1246 if (prefs
.header_mode
== HD_PATH
|| prefs
.header_mode
== HD_BOTH
)
1247 rb
->lcd_putsxy(0, header_height
- pf
->height
, file_name
);
1250 static void viewer_show_footer(void)
1252 if (prefs
.footer_mode
== FT_SBAR
|| prefs
.footer_mode
== FT_BOTH
)
1253 rb
->gui_syncstatusbar_draw(rb
->statusbars
, true);
1255 if (prefs
.footer_mode
== FT_PAGE
|| prefs
.footer_mode
== FT_BOTH
)
1257 unsigned char buf
[12];
1260 rb
->snprintf(buf
, sizeof(buf
), "%d", cpage
);
1262 rb
->snprintf(buf
, sizeof(buf
), "%d - %d", cpage
, cpage
+1);
1264 rb
->lcd_putsxy(0, LCD_HEIGHT
- footer_height
, buf
);
1269 /* We draw a diacritic char over a non-diacritic one. Therefore, such chars are
1270 * not considered to occupy space, therefore buffers might have more than
1271 * max_columns characters. The DIACRITIC_FACTOR is the max ratio between all
1272 * characters and non-diacritic characters in the buffer
1274 #define DIACRITIC_FACTOR 2
1276 static void viewer_draw(int col
)
1278 int i
, j
, k
, line_len
, line_width
, spaces
, left_col
=0;
1279 int width
, extra_spaces
, indent_spaces
, spaces_per_word
, spaces_width
;
1280 bool multiple_spacing
, line_is_short
;
1282 unsigned char *str
, *oldstr
;
1283 unsigned char *line_begin
;
1284 unsigned char *line_end
;
1286 int max_chars
= max_columns
* DIACRITIC_FACTOR
;
1287 unsigned char scratch_buffer
[max_chars
+ 1];
1288 unsigned char utf8_buffer
[max_chars
* 4 + 1];
1289 unsigned char *endptr
;
1291 /* If col==-1 do all calculations but don't display */
1293 #ifdef HAVE_LCD_BITMAP
1294 left_col
= prefs
.need_scrollbar
? SCROLLBAR_WIDTH
:0;
1298 rb
->lcd_clear_display();
1301 line_begin
= line_end
= screen_top_ptr
;
1303 for (i
= 0; i
< display_lines
; i
++) {
1304 if (BUFFER_OOB(line_end
))
1307 break; /* Happens after display last line at BUFFER_EOF() */
1309 if (lpage
== 0 && cline
== 1)
1312 last_screen_top_ptr
= screen_top_ptr
;
1313 last_file_pos
= file_pos
;
1317 get_next_line_position(&line_begin
, &line_end
, &line_is_short
);
1318 if (line_end
== NULL
)
1320 if (BUFFER_OOB(line_begin
))
1322 line_end
= buffer_end
+ 1;
1325 line_len
= line_end
- line_begin
;
1327 /* calculate line_len */
1328 str
= oldstr
= line_begin
;
1330 while (str
< line_end
) {
1332 str
= crop_at_width(str
);
1340 /* width of un-displayed part of the line */
1341 line_width
= j
*draw_columns
;
1343 while (oldstr
< line_end
) {
1344 oldstr
= get_ucs(oldstr
, &ch
);
1345 /* add width of displayed part of the line */
1348 int dw
= glyph_width(ch
);
1350 /* avoid counting spaces at the end of the line */
1357 line_width
+= dw
+ spaces_width
;
1363 if (prefs
.line_mode
== JOIN
) {
1364 if (line_begin
[0] == 0) {
1366 if (prefs
.word_mode
== CHOP
)
1371 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
1382 scratch_buffer
[k
++] = ' ';
1387 scratch_buffer
[k
++] = ' ';
1388 if (k
== max_chars
- 1)
1391 scratch_buffer
[k
++] = c
;
1396 scratch_buffer
[k
] = 0;
1397 endptr
= decode2utf8(scratch_buffer
, utf8_buffer
, col
, draw_columns
);
1401 else if (prefs
.line_mode
== REFLOW
) {
1402 if (line_begin
[0] == 0) {
1404 if (prefs
.word_mode
== CHOP
)
1411 if (!line_is_short
) {
1412 multiple_spacing
= false;
1414 for (str
= line_begin
; str
< line_end
; ) {
1415 str
= get_ucs(str
, &ch
);
1419 if ((str
== line_begin
) && (prefs
.word_mode
==WRAP
))
1420 /* special case: indent the paragraph,
1421 * don't count spaces */
1422 indent_spaces
= par_indent_spaces
;
1423 else if (!multiple_spacing
)
1425 multiple_spacing
= true;
1428 multiple_spacing
= false;
1429 width
+= glyph_width(ch
);
1433 if (multiple_spacing
) spaces
--;
1436 /* total number of spaces to insert between words */
1437 extra_spaces
= (max_width
-width
)/glyph_width(' ')
1439 /* number of spaces between each word*/
1440 spaces_per_word
= extra_spaces
/ spaces
;
1441 /* number of words with n+1 spaces (to fill up) */
1442 extra_spaces
= extra_spaces
% spaces
;
1443 if (spaces_per_word
> 2) { /* too much spacing is awful */
1444 spaces_per_word
= 3;
1447 } else { /* this doesn't matter much... no spaces anyway */
1448 spaces_per_word
= extra_spaces
= 0;
1450 } else { /* end of a paragraph: don't fill line */
1451 spaces_per_word
= 1;
1455 multiple_spacing
= false;
1456 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
1464 if (j
==0 && prefs
.word_mode
==WRAP
) { /* indent paragraph */
1465 for (j
=0; j
<par_indent_spaces
; j
++)
1466 scratch_buffer
[k
++] = ' ';
1469 else if (!multiple_spacing
) {
1470 for (width
= spaces
<extra_spaces
? -1:0; width
< spaces_per_word
; width
++)
1471 scratch_buffer
[k
++] = ' ';
1474 multiple_spacing
= true;
1477 scratch_buffer
[k
++] = c
;
1478 multiple_spacing
= false;
1483 scratch_buffer
[k
] = 0;
1484 endptr
= decode2utf8(scratch_buffer
, utf8_buffer
, col
, draw_columns
);
1488 else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */
1489 if ((col
!= -1) && (line_width
> col
)) {
1490 str
= oldstr
= line_begin
;
1493 while( (width
<draw_columns
) && (oldstr
<line_end
) )
1495 oldstr
= get_ucs(oldstr
, &ch
);
1497 k
-= glyph_width(ch
);
1498 line_begin
= oldstr
;
1500 width
+= glyph_width(ch
);
1504 if(prefs
.view_mode
==WIDE
)
1505 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1506 prefs
.encoding
, oldstr
-line_begin
);
1508 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1509 prefs
.encoding
, line_end
-line_begin
);
1514 /* display on screen the displayed part of the line */
1515 if (col
!= -1 && line_width
> col
)
1517 int dpage
= (cline
+i
<= display_lines
)?cpage
:cpage
+1;
1518 int dline
= cline
+i
- ((cline
+i
<= display_lines
)?0:display_lines
);
1519 bool bflag
= (viewer_find_bookmark(dpage
, dline
) >= 0);
1520 #ifdef HAVE_LCD_BITMAP
1521 int dy
= i
* pf
->height
+ header_height
;
1522 int dx
= (prefs
.alignment
== LEFT
) ? left_col
: LCD_WIDTH
- line_width
;
1525 #ifdef HAVE_LCD_BITMAP
1527 rb
->lcd_set_drawmode(DRMODE_BG
|DRMODE_FG
);
1528 rb
->lcd_fillrect(left_col
, dy
, LCD_WIDTH
- left_col
, pf
->height
);
1529 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
1531 rb
->lcd_putsxy(dx
, dy
, utf8_buffer
);
1532 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1535 rb
->lcd_puts(left_col
, i
, BOOKMARK_ICON
);
1537 rb
->lcd_puts(left_col
+1, i
, utf8_buffer
);
1540 if (line_width
> max_line_len
)
1541 max_line_len
= line_width
;
1544 next_line_ptr
= line_end
;
1546 next_screen_ptr
= line_end
;
1547 if (BUFFER_OOB(next_screen_ptr
))
1548 next_screen_ptr
= NULL
;
1550 #ifdef HAVE_LCD_BITMAP
1551 next_screen_to_draw_ptr
= prefs
.page_mode
==OVERLAP
? line_begin
: next_screen_ptr
;
1553 if (prefs
.need_scrollbar
)
1556 next_screen_to_draw_ptr
= next_screen_ptr
;
1559 #ifdef HAVE_LCD_BITMAP
1561 viewer_show_header();
1564 viewer_show_footer();
1571 static void viewer_top(void)
1573 /* Read top of file into buffer
1574 and point screen pointer to top */
1577 rb
->splash(0, "Loading...");
1580 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1581 fill_buffer(0, buffer
, buffer_size
);
1584 screen_top_ptr
= buffer
;
1589 static void viewer_bottom(void)
1591 unsigned char *line_begin
;
1592 unsigned char *line_end
;
1594 rb
->splash(0, "Loading...");
1596 if (last_screen_top_ptr
)
1600 screen_top_ptr
= last_screen_top_ptr
;
1601 file_pos
= last_file_pos
;
1602 fill_buffer(file_pos
, buffer
, buffer_size
);
1603 buffer_end
= BUFFER_END();
1607 line_end
= screen_top_ptr
;
1609 while (!BUFFER_EOF() || !BUFFER_OOB(line_end
))
1611 get_next_line_position(&line_begin
, &line_end
, NULL
);
1612 if (line_end
== NULL
)
1615 increment_current_line();
1617 screen_top_ptr
= line_end
;
1621 last_screen_top_ptr
= screen_top_ptr
;
1622 last_file_pos
= file_pos
;
1623 buffer_end
= BUFFER_END();
1626 #ifdef HAVE_LCD_BITMAP
1627 static void init_need_scrollbar(void) {
1628 /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
1629 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
1631 prefs
.need_scrollbar
= NEED_SCROLLBAR();
1632 draw_columns
= prefs
.need_scrollbar
? display_columns
-SCROLLBAR_WIDTH
: display_columns
;
1633 par_indent_spaces
= draw_columns
/(5*glyph_width(' '));
1637 static void init_header_and_footer(void)
1641 if (rb
->global_settings
->statusbar
== STATUSBAR_TOP
)
1643 if (prefs
.header_mode
== HD_SBAR
|| prefs
.header_mode
== HD_BOTH
)
1644 header_height
= STATUSBAR_HEIGHT
;
1646 if (prefs
.footer_mode
== FT_SBAR
)
1647 prefs
.footer_mode
= FT_NONE
;
1648 else if (prefs
.footer_mode
== FT_BOTH
)
1649 prefs
.footer_mode
= FT_PAGE
;
1651 else if (rb
->global_settings
->statusbar
== STATUSBAR_BOTTOM
)
1653 if (prefs
.footer_mode
== FT_SBAR
|| prefs
.footer_mode
== FT_BOTH
)
1654 footer_height
= STATUSBAR_HEIGHT
;
1656 if (prefs
.header_mode
== HD_SBAR
)
1657 prefs
.header_mode
= HD_NONE
;
1658 else if (prefs
.header_mode
== HD_BOTH
)
1659 prefs
.header_mode
= HD_PATH
;
1661 else /* STATUSBAR_OFF || STATUSBAR_CUSTOM */
1663 if (prefs
.header_mode
== HD_SBAR
)
1664 prefs
.header_mode
= HD_NONE
;
1665 else if (prefs
.header_mode
== HD_BOTH
)
1666 prefs
.header_mode
= HD_PATH
;
1668 if (prefs
.footer_mode
== FT_SBAR
)
1669 prefs
.footer_mode
= FT_NONE
;
1670 else if (prefs
.footer_mode
== FT_BOTH
)
1671 prefs
.footer_mode
= FT_PAGE
;
1674 if (prefs
.header_mode
== HD_NONE
|| prefs
.header_mode
== HD_PATH
||
1675 prefs
.footer_mode
== FT_NONE
|| prefs
.footer_mode
== FT_PAGE
)
1676 rb
->gui_syncstatusbar_draw(rb
->statusbars
, false);
1678 if (prefs
.header_mode
== HD_PATH
|| prefs
.header_mode
== HD_BOTH
)
1679 header_height
+= pf
->height
;
1680 if (prefs
.footer_mode
== FT_PAGE
|| prefs
.footer_mode
== FT_BOTH
)
1681 footer_height
+= pf
->height
;
1683 display_lines
= (LCD_HEIGHT
- header_height
- footer_height
) / pf
->height
;
1687 last_screen_top_ptr
= NULL
;
1690 static bool change_font(unsigned char *font
)
1692 unsigned char buf
[MAX_PATH
];
1694 if (font
== NULL
|| *font
== '\0')
1697 rb
->snprintf(buf
, MAX_PATH
, "%s/%s.fnt", FONT_DIR
, font
);
1698 if (rb
->font_load(NULL
, buf
) < 0) {
1699 rb
->splash(HZ
/2, "Font load failed.");
1707 static bool viewer_init(void)
1709 #ifdef HAVE_LCD_BITMAP
1710 /* initialize fonts */
1711 pf
= rb
->font_get(FONT_UI
);
1715 draw_columns
= display_columns
= LCD_WIDTH
;
1717 /* REAL fixed pitch :) all chars use up 1 cell */
1719 draw_columns
= display_columns
= 11;
1720 par_indent_spaces
= 2;
1723 fd
= rb
->open(file_name
, O_RDONLY
);
1727 /* Init mac_text value used in processing buffer */
1733 /* When a file is UTF-8 file with BOM, if prefs.encoding is UTF-8,
1734 * then file size decreases only BOM_SIZE.
1736 static void get_filesize(void)
1738 file_size
= rb
->filesize(fd
);
1739 if (file_size
== -1)
1742 if (prefs
.encoding
== UTF_8
&& is_bom
)
1743 file_size
-= BOM_SIZE
;
1746 static int bm_comp(const void *a
, const void *b
)
1748 struct bookmark_info
*pa
;
1749 struct bookmark_info
*pb
;
1751 pa
= (struct bookmark_info
*)a
;
1752 pb
= (struct bookmark_info
*)b
;
1754 if (pa
->page
!= pb
->page
)
1755 return pa
->page
- pb
->page
;
1757 return pa
->line
- pb
->line
;
1760 static void viewer_add_bookmark(void)
1762 if (bookmark_count
>= MAX_BOOKMARKS
-1)
1765 bookmarks
[bookmark_count
].file_position
1766 = file_pos
+ screen_top_ptr
- buffer
;
1767 bookmarks
[bookmark_count
].page
= cpage
;
1768 bookmarks
[bookmark_count
].line
= cline
;
1769 bookmarks
[bookmark_count
].flag
= BOOKMARK_USER
;
1773 static int viewer_add_last_read_bookmark(void)
1777 i
= viewer_find_bookmark(cpage
, cline
);
1779 bookmarks
[i
].flag
|= BOOKMARK_LAST
;
1782 viewer_add_bookmark();
1783 i
= bookmark_count
-1;
1784 bookmarks
[i
].flag
= BOOKMARK_LAST
;
1789 static void viewer_remove_bookmark(int i
)
1793 if (i
< 0 || i
>= bookmark_count
)
1796 for (j
= i
+1; j
< bookmark_count
; j
++)
1797 rb
->memcpy(&bookmarks
[j
-1], &bookmarks
[j
],
1798 sizeof(struct bookmark_info
));
1803 static void viewer_remove_last_read_bookmark(void)
1807 for (i
= 0; i
< bookmark_count
; i
++)
1809 if (bookmarks
[i
].flag
& BOOKMARK_LAST
)
1811 if (bookmarks
[i
].flag
== BOOKMARK_LAST
)
1813 for (j
= i
+1; j
< bookmark_count
; j
++)
1814 rb
->memcpy(&bookmarks
[j
-1], &bookmarks
[j
],
1815 sizeof(struct bookmark_info
));
1820 bookmarks
[i
].flag
= BOOKMARK_USER
;
1826 static int viewer_get_last_read_bookmark(void)
1830 for (i
= 0; i
< bookmark_count
; i
++)
1832 if (bookmarks
[i
].flag
& BOOKMARK_LAST
)
1838 static void viewer_select_bookmark(int initval
)
1847 struct opt_items items
[bookmark_count
];
1848 unsigned char names
[bookmark_count
][38];
1850 if (initval
>= 0 && initval
< bookmark_count
)
1852 ipage
= bookmarks
[initval
].page
;
1853 iline
= bookmarks
[initval
].line
;
1856 rb
->qsort(bookmarks
, bookmark_count
, sizeof(struct bookmark_info
),
1859 for (i
= 0; i
< bookmark_count
; i
++)
1861 rb
->snprintf(names
[i
], sizeof(names
[0]),
1862 #if CONFIG_KEYPAD != PLAYER_PAD
1863 "%sPage: %d Line: %d",
1867 (bookmarks
[i
].flag
&BOOKMARK_LAST
)? "*":" ",
1870 items
[i
].string
= names
[i
];
1871 items
[i
].voice_id
= -1;
1872 if (selected
< 0 && bookmarks
[i
].page
== ipage
&& bookmarks
[i
].line
== iline
)
1876 rb
->set_option("Select bookmark", &selected
, INT
, items
,
1877 sizeof(items
) / sizeof(items
[0]), NULL
);
1879 if (selected
< 0 || selected
>= bookmark_count
)
1881 if (initval
< 0 || (selected
= viewer_get_last_read_bookmark()) < 0)
1884 rb
->splash(HZ
, "Start the first page.");
1886 screen_top_ptr
= buffer
;
1889 buffer_end
= BUFFER_END();
1894 screen_pos
= bookmarks
[selected
].file_position
;
1895 screen_top
= screen_pos
% buffer_size
;
1896 file_pos
= screen_pos
- screen_top
;
1897 screen_top_ptr
= buffer
+ screen_top
;
1898 cpage
= bookmarks
[selected
].page
;
1899 cline
= bookmarks
[selected
].line
;
1900 buffer_end
= BUFFER_END();
1903 static void viewer_default_preferences(void)
1905 prefs
.word_mode
= WRAP
;
1906 prefs
.line_mode
= NORMAL
;
1907 prefs
.view_mode
= NARROW
;
1908 prefs
.alignment
= LEFT
;
1909 prefs
.scroll_mode
= PAGE
;
1910 prefs
.page_mode
= NO_OVERLAP
;
1911 prefs
.scrollbar_mode
= SB_OFF
;
1912 rb
->memset(prefs
.font
, 0, MAX_PATH
);
1913 #ifdef HAVE_LCD_BITMAP
1914 prefs
.header_mode
= HD_BOTH
;
1915 prefs
.footer_mode
= FT_BOTH
;
1916 rb
->snprintf(prefs
.font
, MAX_PATH
, "%s", rb
->global_settings
->font_file
);
1918 prefs
.header_mode
= HD_NONE
;
1919 prefs
.footer_mode
= FT_NONE
;
1921 prefs
.autoscroll_speed
= 1;
1922 /* Set codepage to system default */
1923 prefs
.encoding
= rb
->global_settings
->default_codepage
;
1926 static bool viewer_read_preferences(int pfd
, int version
)
1928 unsigned char buf
[PREFERENCES_SIZE
];
1929 unsigned char *p
= buf
;
1931 if (rb
->read(pfd
, buf
, sizeof(buf
)) != sizeof(buf
))
1934 prefs
.word_mode
= *p
++;
1935 prefs
.line_mode
= *p
++;
1936 prefs
.view_mode
= *p
++;
1938 prefs
.alignment
= *p
++;
1940 prefs
.alignment
= LEFT
;
1941 prefs
.encoding
= *p
++;
1942 prefs
.scrollbar_mode
= *p
++;
1943 prefs
.need_scrollbar
= *p
++;
1944 prefs
.page_mode
= *p
++;
1945 prefs
.header_mode
= *p
++;
1946 prefs
.footer_mode
= *p
++;
1947 prefs
.scroll_mode
= *p
++;
1948 prefs
.autoscroll_speed
= *p
++;
1949 rb
->memcpy(prefs
.font
, p
, MAX_PATH
);
1953 static bool viewer_write_preferences(int pfd
)
1955 unsigned char buf
[PREFERENCES_SIZE
];
1956 unsigned char *p
= buf
;
1958 *p
++ = prefs
.word_mode
;
1959 *p
++ = prefs
.line_mode
;
1960 *p
++ = prefs
.view_mode
;
1961 *p
++ = prefs
.alignment
;
1962 *p
++ = prefs
.encoding
;
1963 *p
++ = prefs
.scrollbar_mode
;
1964 *p
++ = prefs
.need_scrollbar
;
1965 *p
++ = prefs
.page_mode
;
1966 *p
++ = prefs
.header_mode
;
1967 *p
++ = prefs
.footer_mode
;
1968 *p
++ = prefs
.scroll_mode
;
1969 *p
++ = prefs
.autoscroll_speed
;
1970 rb
->memcpy(p
, prefs
.font
, MAX_PATH
);
1972 return (rb
->write(pfd
, buf
, sizeof(buf
)) == sizeof(buf
));
1975 static bool viewer_read_bookmark_info(int bfd
, struct bookmark_info
*b
)
1977 unsigned char buf
[BOOKMARK_SIZE
];
1979 if (rb
->read(bfd
, buf
, sizeof(buf
)) != sizeof(buf
))
1982 b
->file_position
= (buf
[0] << 24)|(buf
[1] << 16)|(buf
[2] << 8)|buf
[3];
1983 b
->page
= (buf
[4] << 8)|buf
[5];
1990 static bool viewer_read_bookmark_infos(int bfd
)
1995 if (rb
->read(bfd
, &c
, 1) != 1)
2002 if (bookmark_count
> MAX_BOOKMARKS
)
2003 bookmark_count
= MAX_BOOKMARKS
;
2005 for (i
= 0; i
< bookmark_count
; i
++)
2007 if (!viewer_read_bookmark_info(bfd
, &bookmarks
[i
]))
2016 static bool viewer_write_bookmark_info(int bfd
, struct bookmark_info
*b
)
2018 unsigned char buf
[BOOKMARK_SIZE
];
2019 unsigned char *p
= buf
;
2022 ul
= b
->file_position
;
2035 return (rb
->write(bfd
, buf
, sizeof(buf
)) == sizeof(buf
));
2038 static bool viewer_write_bookmark_infos(int bfd
)
2040 unsigned char c
= bookmark_count
;
2043 if (rb
->write(bfd
, &c
, 1) != 1)
2046 for (i
= 0; i
< bookmark_count
; i
++)
2048 if (!viewer_write_bookmark_info(bfd
, &bookmarks
[i
]))
2055 static bool viewer_load_global_settings(void)
2057 unsigned buf
[GLOBAL_SETTINGS_H_SIZE
];
2058 int sfd
= rb
->open(GLOBAL_SETTINGS_FILE
, O_RDONLY
);
2065 if ((rb
->read(sfd
, buf
, GLOBAL_SETTINGS_H_SIZE
) == GLOBAL_SETTINGS_H_SIZE
) ||
2066 (rb
->memcmp(buf
, GLOBAL_SETTINGS_HEADER
, GLOBAL_SETTINGS_H_SIZE
- 1) == 0))
2068 version
= buf
[GLOBAL_SETTINGS_H_SIZE
- 1] - GLOBAL_SETTINGS_FIRST_VERSION
;
2069 res
= viewer_read_preferences(sfd
, version
);
2075 static bool viewer_save_global_settings(void)
2077 int sfd
= rb
->open(GLOBAL_SETTINGS_TMP_FILE
, O_WRONLY
|O_CREAT
|O_TRUNC
);
2082 if (rb
->write(sfd
, &GLOBAL_SETTINGS_HEADER
, GLOBAL_SETTINGS_H_SIZE
)
2083 != GLOBAL_SETTINGS_H_SIZE
||
2084 !viewer_write_preferences(sfd
))
2087 rb
->remove(GLOBAL_SETTINGS_TMP_FILE
);
2091 rb
->remove(GLOBAL_SETTINGS_FILE
);
2092 rb
->rename(GLOBAL_SETTINGS_TMP_FILE
, GLOBAL_SETTINGS_FILE
);
2096 static bool viewer_load_settings(void)
2098 unsigned char buf
[MAX_PATH
+2];
2099 unsigned int fcount
;
2106 sfd
= rb
->open(SETTINGS_FILE
, O_RDONLY
);
2110 if ((rb
->read(sfd
, buf
, SETTINGS_H_SIZE
+2) != SETTINGS_H_SIZE
+2) ||
2111 rb
->memcmp(buf
, SETTINGS_HEADER
, SETTINGS_H_SIZE
- 1))
2113 /* illegal setting file */
2116 if (rb
->file_exists(SETTINGS_FILE
))
2117 rb
->remove(SETTINGS_FILE
);
2122 version
= buf
[SETTINGS_H_SIZE
- 1] - SETTINGS_FIRST_VERSION
;
2123 fcount
= (buf
[SETTINGS_H_SIZE
] << 8) | buf
[SETTINGS_H_SIZE
+1];
2124 for (i
= 0; i
< fcount
; i
++)
2126 if (rb
->read(sfd
, buf
, MAX_PATH
+2) != MAX_PATH
+2)
2129 size
= (buf
[MAX_PATH
] << 8) | buf
[MAX_PATH
+1];
2130 if (rb
->strcmp(buf
, file_name
))
2132 if (rb
->lseek(sfd
, size
, SEEK_CUR
) < 0)
2136 if (!viewer_read_preferences(sfd
, version
))
2139 res
= viewer_read_bookmark_infos(sfd
);
2148 /* load global settings */
2149 if (!viewer_load_global_settings())
2150 viewer_default_preferences();
2153 screen_top_ptr
= buffer
;
2159 rb
->memcpy(&old_prefs
, &prefs
, sizeof(struct preferences
));
2162 if (bookmark_count
> 1)
2163 viewer_select_bookmark(-1);
2164 else if (bookmark_count
== 1)
2169 screen_pos
= bookmarks
[0].file_position
;
2170 screen_top
= screen_pos
% buffer_size
;
2171 file_pos
= screen_pos
- screen_top
;
2172 screen_top_ptr
= buffer
+ screen_top
;
2173 cpage
= bookmarks
[0].page
;
2174 cline
= bookmarks
[0].line
;
2177 viewer_remove_last_read_bookmark();
2182 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
2184 if (BUFFER_OOB(screen_top_ptr
))
2185 screen_top_ptr
= buffer
;
2187 fill_buffer(file_pos
, buffer
, buffer_size
);
2188 if (prefs
.scroll_mode
== PAGE
&& cline
> 1)
2189 viewer_scroll_to_top_line();
2191 /* remember the current position */
2192 start_position
= file_pos
+ screen_top_ptr
- buffer
;
2194 #ifdef HAVE_LCD_BITMAP
2195 /* load prefs font if it is different than the global settings font */
2196 if (rb
->strcmp(prefs
.font
, rb
->global_settings
->font_file
)) {
2197 if (!change_font(prefs
.font
)) {
2198 /* fallback by resetting prefs font to the global settings font */
2199 rb
->memset(prefs
.font
, 0, MAX_PATH
);
2200 rb
->snprintf(prefs
.font
, MAX_PATH
, "%s",
2201 rb
->global_settings
->font_file
);
2203 if (!change_font(prefs
.font
))
2208 init_need_scrollbar();
2209 init_header_and_footer();
2215 static bool copy_bookmark_file(int sfd
, int dfd
, off_t start
, off_t size
)
2219 if (rb
->lseek(sfd
, start
, SEEK_SET
) < 0)
2224 if (size
> buffer_size
)
2225 rsize
= buffer_size
;
2230 if (rb
->read(sfd
, buffer
, rsize
) != rsize
||
2231 rb
->write(dfd
, buffer
, rsize
) != rsize
)
2237 static bool viewer_save_settings(void)
2239 unsigned char buf
[MAX_PATH
+2];
2240 unsigned int fcount
= 0;
2245 off_t first_copy_size
= 0;
2246 off_t second_copy_start_pos
= 0;
2249 /* add reading page to bookmarks */
2250 idx
= viewer_find_bookmark(cpage
, cline
);
2252 bookmarks
[idx
].flag
|= BOOKMARK_LAST
;
2255 viewer_add_bookmark();
2256 bookmarks
[bookmark_count
-1].flag
= BOOKMARK_LAST
;
2259 tfd
= rb
->open(SETTINGS_TMP_FILE
, O_WRONLY
|O_CREAT
|O_TRUNC
);
2263 ofd
= rb
->open(SETTINGS_FILE
, O_RDWR
);
2266 if ((rb
->read(ofd
, buf
, SETTINGS_H_SIZE
+2) != SETTINGS_H_SIZE
+2) ||
2267 rb
->memcmp(buf
, SETTINGS_HEADER
, SETTINGS_H_SIZE
))
2272 fcount
= (buf
[SETTINGS_H_SIZE
] << 8) | buf
[SETTINGS_H_SIZE
+1];
2274 for (i
= 0; i
< fcount
; i
++)
2276 if (rb
->read(ofd
, buf
, MAX_PATH
+2) != MAX_PATH
+2)
2281 size
= (buf
[MAX_PATH
] << 8) | buf
[MAX_PATH
+1];
2282 if (rb
->strcmp(buf
, file_name
))
2284 if (rb
->lseek(ofd
, size
, SEEK_CUR
) < 0)
2292 first_copy_size
= rb
->lseek(ofd
, 0, SEEK_CUR
);
2293 if (first_copy_size
< 0)
2298 second_copy_start_pos
= first_copy_size
+ size
;
2299 first_copy_size
-= MAX_PATH
+2;
2304 if (first_copy_size
== 0)
2305 first_copy_size
= rb
->filesize(ofd
);
2307 if (!copy_bookmark_file(ofd
, tfd
, 0, first_copy_size
))
2312 if (second_copy_start_pos
> 0)
2314 if (!copy_bookmark_file(ofd
, tfd
, second_copy_start_pos
,
2315 rb
->filesize(ofd
) - second_copy_start_pos
))
2325 rb
->memcpy(buf
, SETTINGS_HEADER
, SETTINGS_H_SIZE
);
2326 buf
[SETTINGS_H_SIZE
] = 0;
2327 buf
[SETTINGS_H_SIZE
+1] = 0;
2328 if (rb
->write(tfd
, buf
, SETTINGS_H_SIZE
+2) != SETTINGS_H_SIZE
+2)
2332 /* copy to current read file's bookmarks */
2333 rb
->memset(buf
, 0, MAX_PATH
);
2334 rb
->snprintf(buf
, MAX_PATH
, "%s", file_name
);
2336 size
= PREFERENCES_SIZE
+ bookmark_count
* BOOKMARK_SIZE
+ 1;
2337 buf
[MAX_PATH
] = size
>> 8;
2338 buf
[MAX_PATH
+1] = size
;
2340 if (rb
->write(tfd
, buf
, MAX_PATH
+2) != MAX_PATH
+2)
2343 if (!viewer_write_preferences(tfd
))
2346 if (!viewer_write_bookmark_infos(tfd
))
2349 if (rb
->lseek(tfd
, SETTINGS_H_SIZE
, SEEK_SET
) < 0)
2353 buf
[0] = fcount
>> 8;
2356 if (rb
->write(tfd
, buf
, 2) != 2)
2361 rb
->remove(SETTINGS_FILE
);
2362 rb
->rename(SETTINGS_TMP_FILE
, SETTINGS_FILE
);
2368 rb
->remove(SETTINGS_TMP_FILE
);
2372 static void viewer_exit(void *parameter
)
2376 /* save preference and bookmarks */
2377 if (!viewer_save_settings())
2378 rb
->splash(HZ
, "Can't save preference and bookmarks.");
2381 #ifdef HAVE_LCD_BITMAP
2382 if (rb
->strcmp(prefs
.font
, rb
->global_settings
->font_file
))
2383 change_font(rb
->global_settings
->font_file
);
2387 static void calc_page(void)
2390 unsigned char *line_begin
;
2391 unsigned char *line_end
;
2393 unsigned char *sstp
;
2395 rb
->splash(0, "Calculating page/line number...");
2397 /* add reading page to bookmarks */
2398 viewer_add_last_read_bookmark();
2400 rb
->qsort(bookmarks
, bookmark_count
, sizeof(struct bookmark_info
),
2406 screen_top_ptr
= buffer
;
2407 buffer_end
= BUFFER_END();
2409 fill_buffer(file_pos
, buffer
, buffer_size
);
2410 line_end
= line_begin
= buffer
;
2412 for (i
= 0; i
< bookmark_count
; i
++)
2414 sfp
= bookmarks
[i
].file_position
;
2417 while ((line_begin
> sstp
|| sstp
>= line_end
) ||
2418 (file_pos
> sfp
|| sfp
>= file_pos
+ BUFFER_END() - buffer
))
2420 get_next_line_position(&line_begin
, &line_end
, NULL
);
2421 if (line_end
== NULL
)
2424 next_line_ptr
= line_end
;
2426 if (sstp
== buffer
&&
2427 file_pos
<= sfp
&& sfp
< file_pos
+ BUFFER_END() - buffer
)
2428 sstp
= sfp
- file_pos
+ buffer
;
2430 increment_current_line();
2433 decrement_current_line();
2434 bookmarks
[i
].page
= cpage
;
2435 bookmarks
[i
].line
= cline
;
2436 bookmarks
[i
].file_position
= file_pos
+ (line_begin
- buffer
);
2437 increment_current_line();
2440 /* remove reading page's bookmark */
2441 for (i
= 0; i
< bookmark_count
; i
++)
2443 if (bookmarks
[i
].flag
& BOOKMARK_LAST
)
2448 screen_pos
= bookmarks
[i
].file_position
;
2449 screen_top
= screen_pos
% buffer_size
;
2450 file_pos
= screen_pos
- screen_top
;
2451 screen_top_ptr
= buffer
+ screen_top
;
2453 cpage
= bookmarks
[i
].page
;
2454 cline
= bookmarks
[i
].line
;
2455 bookmarks
[i
].flag
^= BOOKMARK_LAST
;
2456 buffer_end
= BUFFER_END();
2458 fill_buffer(file_pos
, buffer
, buffer_size
);
2460 if (bookmarks
[i
].flag
== 0)
2461 viewer_remove_bookmark(i
);
2463 if (prefs
.scroll_mode
== PAGE
&& cline
> 1)
2464 viewer_scroll_to_top_line();
2470 static int col_limit(int col
)
2475 if (col
>= max_width
- draw_columns
)
2476 col
= max_width
- draw_columns
;
2481 /* settings helper functions */
2483 static bool encoding_setting(void)
2485 static struct opt_items names
[NUM_CODEPAGES
];
2488 enum codepages oldenc
= prefs
.encoding
;
2490 for (idx
= 0; idx
< NUM_CODEPAGES
; idx
++)
2492 names
[idx
].string
= rb
->get_codepage_name(idx
);
2493 names
[idx
].voice_id
= -1;
2496 res
= rb
->set_option("Encoding", &prefs
.encoding
, INT
, names
,
2497 sizeof(names
) / sizeof(names
[0]), NULL
);
2499 /* When prefs.encoding changes into UTF-8 or changes from UTF-8,
2500 * filesize (file_size) might change.
2501 * In addition, if prefs.encoding is UTF-8, then BOM does not read.
2503 if (oldenc
!= prefs
.encoding
&& (oldenc
== UTF_8
|| prefs
.encoding
== UTF_8
))
2507 fill_buffer(file_pos
, buffer
, buffer_size
);
2513 static bool word_wrap_setting(void)
2515 static const struct opt_items names
[] = {
2517 {"Off (Chop Words)", -1},
2520 return rb
->set_option("Word Wrap", &prefs
.word_mode
, INT
,
2524 static bool line_mode_setting(void)
2526 static const struct opt_items names
[] = {
2529 {"Expand Lines", -1},
2530 #ifdef HAVE_LCD_BITMAP
2531 {"Reflow Lines", -1},
2535 return rb
->set_option("Line Mode", &prefs
.line_mode
, INT
, names
,
2536 sizeof(names
) / sizeof(names
[0]), NULL
);
2539 static bool view_mode_setting(void)
2541 static const struct opt_items names
[] = {
2542 {"No (Narrow)", -1},
2546 ret
= rb
->set_option("Wide View", &prefs
.view_mode
, INT
,
2548 if (prefs
.view_mode
== NARROW
)
2554 static bool scroll_mode_setting(void)
2556 static const struct opt_items names
[] = {
2557 {"Scroll by Page", -1},
2558 {"Scroll by Line", -1},
2561 return rb
->set_option("Scroll Mode", &prefs
.scroll_mode
, INT
,
2565 #ifdef HAVE_LCD_BITMAP
2566 static bool page_mode_setting(void)
2568 static const struct opt_items names
[] = {
2573 return rb
->set_option("Overlap Pages", &prefs
.page_mode
, INT
,
2577 static bool scrollbar_setting(void)
2579 static const struct opt_items names
[] = {
2584 return rb
->set_option("Show Scrollbar", &prefs
.scrollbar_mode
, INT
,
2588 static bool header_setting(void)
2590 int len
= (rb
->global_settings
->statusbar
== STATUSBAR_TOP
)? 4 : 2;
2591 struct opt_items names
[len
];
2593 names
[0].string
= "None";
2594 names
[0].voice_id
= -1;
2595 names
[1].string
= "File path";
2596 names
[1].voice_id
= -1;
2598 if (rb
->global_settings
->statusbar
== STATUSBAR_TOP
)
2600 names
[2].string
= "Status bar";
2601 names
[2].voice_id
= -1;
2602 names
[3].string
= "Both";
2603 names
[3].voice_id
= -1;
2606 return rb
->set_option("Show Header", &prefs
.header_mode
, INT
,
2610 static bool footer_setting(void)
2612 int len
= (rb
->global_settings
->statusbar
== STATUSBAR_BOTTOM
)? 4 : 2;
2613 struct opt_items names
[len
];
2615 names
[0].string
= "None";
2616 names
[0].voice_id
= -1;
2617 names
[1].string
= "Page Num";
2618 names
[1].voice_id
= -1;
2620 if (rb
->global_settings
->statusbar
== STATUSBAR_BOTTOM
)
2622 names
[2].string
= "Status bar";
2623 names
[2].voice_id
= -1;
2624 names
[3].string
= "Both";
2625 names
[3].voice_id
= -1;
2628 return rb
->set_option("Show Footer", &prefs
.footer_mode
, INT
,
2632 static int font_comp(const void *a
, const void *b
)
2634 struct opt_items
*pa
;
2635 struct opt_items
*pb
;
2637 pa
= (struct opt_items
*)a
;
2638 pb
= (struct opt_items
*)b
;
2640 return rb
->strcmp(pa
->string
, pb
->string
);
2643 static bool font_setting(void)
2647 struct dirent
*entry
;
2655 dir
= rb
->opendir(FONT_DIR
);
2658 rb
->splash(HZ
/2, "Font dir is not accessible");
2664 entry
= rb
->readdir(dir
);
2669 len
= rb
->strlen(entry
->d_name
);
2670 if (len
< 4 || rb
->strcmp(entry
->d_name
+ len
-4, ".fnt"))
2677 struct opt_items names
[count
];
2678 unsigned char font_names
[size
];
2679 unsigned char *p
= font_names
;
2681 dir
= rb
->opendir(FONT_DIR
);
2684 rb
->splash(HZ
/2, "Font dir is not accessible");
2690 entry
= rb
->readdir(dir
);
2695 len
= rb
->strlen(entry
->d_name
);
2696 if (len
< 4 || rb
->strcmp(entry
->d_name
+ len
-4, ".fnt"))
2699 rb
->snprintf(p
, len
-3, "%s", entry
->d_name
);
2700 names
[i
].string
= p
;
2701 names
[i
].voice_id
= -1;
2709 rb
->qsort(names
, count
, sizeof(struct opt_items
), font_comp
);
2711 for (i
= 0; i
< count
; i
++)
2713 if (!rb
->strcmp(names
[i
].string
, prefs
.font
))
2719 old_font
= new_font
;
2721 res
= rb
->set_option("Select Font", &new_font
, INT
,
2722 names
, count
, NULL
);
2724 if (new_font
!= old_font
)
2726 /* load selected font */
2727 if (!change_font((unsigned char *)names
[new_font
].string
)) {
2728 /* revert by re-loading the preferences font */
2729 change_font(prefs
.font
);
2732 rb
->memset(prefs
.font
, 0, MAX_PATH
);
2733 rb
->snprintf(prefs
.font
, MAX_PATH
, "%s", names
[new_font
].string
);
2739 static bool alignment_setting(void)
2741 static const struct opt_items names
[] = {
2746 return rb
->set_option("Alignment", &prefs
.alignment
, INT
,
2751 static bool autoscroll_speed_setting(void)
2753 return rb
->set_int("Auto-scroll Speed", "", UNIT_INT
,
2754 &prefs
.autoscroll_speed
, NULL
, 1, 1, 10, NULL
);
2757 MENUITEM_FUNCTION(encoding_item
, 0, "Encoding", encoding_setting
,
2758 NULL
, NULL
, Icon_NOICON
);
2759 MENUITEM_FUNCTION(word_wrap_item
, 0, "Word Wrap", word_wrap_setting
,
2760 NULL
, NULL
, Icon_NOICON
);
2761 MENUITEM_FUNCTION(line_mode_item
, 0, "Line Mode", line_mode_setting
,
2762 NULL
, NULL
, Icon_NOICON
);
2763 MENUITEM_FUNCTION(view_mode_item
, 0, "Wide View", view_mode_setting
,
2764 NULL
, NULL
, Icon_NOICON
);
2765 #ifdef HAVE_LCD_BITMAP
2766 MENUITEM_FUNCTION(alignment_item
, 0, "Alignment", alignment_setting
,
2767 NULL
, NULL
, Icon_NOICON
);
2768 MENUITEM_FUNCTION(scrollbar_item
, 0, "Show Scrollbar", scrollbar_setting
,
2769 NULL
, NULL
, Icon_NOICON
);
2770 MENUITEM_FUNCTION(page_mode_item
, 0, "Overlap Pages", page_mode_setting
,
2771 NULL
, NULL
, Icon_NOICON
);
2772 MENUITEM_FUNCTION(header_item
, 0, "Show Header", header_setting
,
2773 NULL
, NULL
, Icon_NOICON
);
2774 MENUITEM_FUNCTION(footer_item
, 0, "Show Footer", footer_setting
,
2775 NULL
, NULL
, Icon_NOICON
);
2776 MENUITEM_FUNCTION(font_item
, 0, "Font", font_setting
,
2777 NULL
, NULL
, Icon_NOICON
);
2779 MENUITEM_FUNCTION(scroll_mode_item
, 0, "Scroll Mode", scroll_mode_setting
,
2780 NULL
, NULL
, Icon_NOICON
);
2781 MENUITEM_FUNCTION(autoscroll_speed_item
, 0, "Auto-Scroll Speed",
2782 autoscroll_speed_setting
, NULL
, NULL
, Icon_NOICON
);
2783 MAKE_MENU(option_menu
, "Viewer Options", NULL
, Icon_NOICON
,
2784 &encoding_item
, &word_wrap_item
, &line_mode_item
, &view_mode_item
,
2785 #ifdef HAVE_LCD_BITMAP
2786 &alignment_item
, &scrollbar_item
, &page_mode_item
, &header_item
,
2787 &footer_item
, &font_item
,
2789 &scroll_mode_item
, &autoscroll_speed_item
);
2791 static bool viewer_options_menu(bool is_global
)
2794 struct preferences tmp_prefs
;
2796 rb
->memcpy(&tmp_prefs
, &prefs
, sizeof(struct preferences
));
2798 result
= (rb
->do_menu(&option_menu
, NULL
, NULL
, false) == MENU_ATTACHED_USB
);
2800 if (!is_global
&& rb
->memcmp(&tmp_prefs
, &prefs
, sizeof(struct preferences
)))
2802 /* Show-scrollbar mode for current view-width mode */
2803 #ifdef HAVE_LCD_BITMAP
2804 init_need_scrollbar();
2805 init_header_and_footer();
2812 static void viewer_menu(void)
2816 MENUITEM_STRINGLIST(menu
, "Viewer Menu", NULL
,
2817 "Return", "Viewer Options",
2818 "Show Playback Menu", "Select Bookmark",
2819 "Global Settings", "Quit");
2821 result
= rb
->do_menu(&menu
, NULL
, NULL
, false);
2824 case 0: /* return */
2826 case 1: /* change settings */
2827 done
= viewer_options_menu(false);
2829 case 2: /* playback control */
2830 playback_control(NULL
);
2832 case 3: /* select bookmark */
2833 viewer_select_bookmark(viewer_add_last_read_bookmark());
2834 viewer_remove_last_read_bookmark();
2835 fill_buffer(file_pos
, buffer
, buffer_size
);
2836 if (prefs
.scroll_mode
== PAGE
&& cline
> 1)
2837 viewer_scroll_to_top_line();
2839 case 4: /* change global settings */
2841 struct preferences orig_prefs
;
2843 rb
->memcpy(&orig_prefs
, &prefs
, sizeof(struct preferences
));
2844 if (!viewer_load_global_settings())
2845 viewer_default_preferences();
2846 done
= viewer_options_menu(true);
2847 viewer_save_global_settings();
2848 rb
->memcpy(&prefs
, &orig_prefs
, sizeof(struct preferences
));
2859 enum plugin_status
plugin_start(const void* file
)
2862 int lastbutton
= BUTTON_NONE
;
2863 bool autoscroll
= false;
2866 old_tick
= *rb
->current_tick
;
2868 /* get the plugin buffer */
2869 buffer
= rb
->plugin_get_buffer((size_t *)&buffer_size
);
2870 if (buffer_size
== 0)
2872 rb
->splash(HZ
, "buffer does not allocate !!");
2873 return PLUGIN_ERROR
;
2875 block_size
= buffer_size
/ 3;
2876 buffer_size
= 3 * block_size
;
2879 return PLUGIN_ERROR
;
2884 rb
->splash(HZ
, "Error opening file.");
2885 return PLUGIN_ERROR
;
2888 if (!viewer_load_settings()) /* load the preferences and bookmark */
2889 return PLUGIN_ERROR
;
2892 rb
->lcd_set_backdrop(NULL
);
2901 if(old_tick
<= *rb
->current_tick
- (110-prefs
.autoscroll_speed
*10))
2903 viewer_scroll_down(true);
2905 old_tick
= *rb
->current_tick
;
2909 button
= rb
->button_get_w_tmo(HZ
/10);
2911 if (prefs
.view_mode
!= WIDE
) {
2912 /* when not in wide view mode, the SCREEN_LEFT and SCREEN_RIGHT
2913 buttons jump to the beginning and end of the file. To stop
2914 users doing this by accident, replace non-held occurrences
2915 with page up/down instead. */
2916 if (button
== VIEWER_SCREEN_LEFT
)
2917 button
= VIEWER_PAGE_UP
;
2918 else if (button
== VIEWER_SCREEN_RIGHT
)
2919 button
= VIEWER_PAGE_DOWN
;
2930 case VIEWER_AUTOSCROLL
:
2931 #ifdef VIEWER_AUTOSCROLL_PRE
2932 if (lastbutton
!= VIEWER_AUTOSCROLL_PRE
)
2935 autoscroll
= !autoscroll
;
2938 case VIEWER_PAGE_UP
:
2939 case VIEWER_PAGE_UP
| BUTTON_REPEAT
:
2940 #ifdef VIEWER_PAGE_UP2
2941 case VIEWER_PAGE_UP2
:
2942 case VIEWER_PAGE_UP2
| BUTTON_REPEAT
:
2944 if (prefs
.scroll_mode
== PAGE
)
2947 #ifdef HAVE_LCD_BITMAP
2948 for (i
= prefs
.page_mode
==OVERLAP
? 1:0; i
< display_lines
; i
++)
2950 for (i
= 0; i
< display_lines
; i
++)
2956 old_tick
= *rb
->current_tick
;
2960 case VIEWER_PAGE_DOWN
:
2961 case VIEWER_PAGE_DOWN
| BUTTON_REPEAT
:
2962 #ifdef VIEWER_PAGE_DOWN2
2963 case VIEWER_PAGE_DOWN2
:
2964 case VIEWER_PAGE_DOWN2
| BUTTON_REPEAT
:
2966 if (prefs
.scroll_mode
== PAGE
)
2969 if (next_screen_ptr
!= NULL
)
2971 screen_top_ptr
= next_screen_to_draw_ptr
;
2972 if (cpage
< MAX_PAGE
)
2977 viewer_scroll_down(autoscroll
);
2978 old_tick
= *rb
->current_tick
;
2982 case VIEWER_SCREEN_LEFT
:
2983 case VIEWER_SCREEN_LEFT
| BUTTON_REPEAT
:
2984 if (prefs
.view_mode
== WIDE
) {
2986 col
= col_limit(col
- draw_columns
);
2988 else { /* prefs.view_mode == NARROW */
2996 case VIEWER_SCREEN_RIGHT
:
2997 case VIEWER_SCREEN_RIGHT
| BUTTON_REPEAT
:
2998 if (prefs
.view_mode
== WIDE
) {
3000 col
= col_limit(col
+ draw_columns
);
3002 else { /* prefs.view_mode == NARROW */
3003 /* Bottom of file */
3010 #ifdef VIEWER_LINE_UP
3011 case VIEWER_LINE_UP
:
3012 case VIEWER_LINE_UP
| BUTTON_REPEAT
:
3013 /* Scroll up one line */
3015 old_tick
= *rb
->current_tick
;
3019 case VIEWER_LINE_DOWN
:
3020 case VIEWER_LINE_DOWN
| BUTTON_REPEAT
:
3021 /* Scroll down one line */
3022 viewer_scroll_down(autoscroll
);
3023 increment_current_line();
3024 old_tick
= *rb
->current_tick
;
3028 #ifdef VIEWER_COLUMN_LEFT
3029 case VIEWER_COLUMN_LEFT
:
3030 case VIEWER_COLUMN_LEFT
| BUTTON_REPEAT
:
3031 if (prefs
.view_mode
== WIDE
) {
3032 /* Scroll left one column */
3033 col
= col_limit(col
- glyph_width('o'));
3038 case VIEWER_COLUMN_RIGHT
:
3039 case VIEWER_COLUMN_RIGHT
| BUTTON_REPEAT
:
3040 if (prefs
.view_mode
== WIDE
) {
3041 /* Scroll right one column */
3042 col
= col_limit(col
+ glyph_width('o'));
3048 #ifdef VIEWER_RC_QUIT
3049 case VIEWER_RC_QUIT
:
3059 case VIEWER_BOOKMARK
:
3061 int idx
= viewer_find_bookmark(cpage
, cline
);
3065 if (bookmark_count
>= MAX_BOOKMARKS
-1)
3066 rb
->splash(HZ
/2, "No more add bookmark.");
3069 viewer_add_bookmark();
3070 rb
->splash(HZ
/2, "Bookmark add.");
3075 viewer_remove_bookmark(idx
);
3076 rb
->splash(HZ
/2, "Bookmark remove.");
3083 if (rb
->default_event_handler_ex(button
, viewer_exit
, NULL
)
3084 == SYS_USB_CONNECTED
)
3085 return PLUGIN_USB_CONNECTED
;
3088 if (button
!= BUTTON_NONE
)
3090 lastbutton
= button
;