Another small bookmark.c revision, no functional change, saves bin size
[kugel-rb.git] / apps / plugins / viewer.c
blob929a2c0ee18dc6ec48fdbad640daaee17d759a6a
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
21 #include "plugin.h"
22 #include <ctype.h>
23 #include "lib/playback_control.h"
25 PLUGIN_HEADER
27 /* global settings file
28 * binary file, so dont use .cfg
30 * setting file format
32 * part byte count
33 * --------------------------------
34 * 'TVGS' 4
35 * version 1
36 * word_mode 1
37 * line_mode 1
38 * view_mode 1
39 * alignment 1
40 * encoding 1
41 * scrollbar_mode 1
42 * need_scrollbar 1
43 * page_mode 1
44 * page_number_mode 1
45 * title_mode 1
46 * scroll_mode 1
47 * autoscroll_speed 1
48 * font name MAX_PATH
50 #define GLOBAL_SETTINGS_FILE VIEWERS_DIR "/viewer.dat"
52 /* temporary file */
53 #define GLOBAL_SETTINGS_TMP_FILE VIEWERS_DIR "/viewer_file.tmp"
55 #define GLOBAL_SETTINGS_HEADER "\x54\x56\x47\x53\x31" /* header="TVGS" version=1 */
56 #define GLOBAL_SETTINGS_H_SIZE 5
58 /* preferences and bookmarks at each file
59 * binary file, so dont use .cfg
61 * setting file format
63 * part byte count
64 * --------------------------------
65 * 'TVS' 3
66 * version 1
67 * file count 2
68 * [1st file]
69 * file path MAX_PATH
70 * next file pos 2
71 * [preferences]
72 * word_mode 1
73 * line_mode 1
74 * view_mode 1
75 * alignment 1
76 * encoding 1
77 * scrollbar_mode 1
78 * need_scrollbar 1
79 * page_mode 1
80 * header_mode 1
81 * footer_mode 1
82 * scroll_mode 1
83 * autoscroll_speed 1
84 * font name MAX_PATH
85 * bookmark count 1
86 * [1st bookmark]
87 * file_position 4
88 * page 2
89 * line 1
90 * flag 1
91 * [2nd bookmark]
92 * ...
93 * [last bookmark]
94 * [2nd file]
95 * ...
96 * [last file]
98 #define SETTINGS_FILE VIEWERS_DIR "/viewer_file.dat"
100 /* temporary file */
101 #define SETTINGS_TMP_FILE VIEWERS_DIR "/viewer_file.tmp"
103 #define SETTINGS_HEADER "\x54\x56\x53\x32" /* header="TVS" version=2 */
104 #define SETTINGS_H_SIZE 4
106 #define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */
107 #define NARROW_MAX_COLUMNS 64 /* Max displayable string len [narrow] (over-estimate) */
108 #define WIDE_MAX_COLUMNS 128 /* Max displayable string len [wide] (over-estimate) */
109 #define MAX_WIDTH 910 /* Max line length in WIDE mode */
110 #define READ_PREV_ZONE (block_size*9/10) /* Arbitrary number less than SMALL_BLOCK_SIZE */
111 #define SMALL_BLOCK_SIZE block_size /* Smallest file chunk we will read */
112 #define LARGE_BLOCK_SIZE (block_size << 1) /* Preferable size of file chunk to read */
113 #define TOP_SECTOR buffer
114 #define MID_SECTOR (buffer + SMALL_BLOCK_SIZE)
115 #define BOTTOM_SECTOR (buffer + (SMALL_BLOCK_SIZE << 1))
116 #undef SCROLLBAR_WIDTH
117 #define SCROLLBAR_WIDTH rb->global_settings->scrollbar_width
118 #define MAX_PAGE 9999
120 #define BOOKMARK_SIZE 8
121 #define MAX_BOOKMARKS 10 /* user setting bookmarks + last read page */
123 #define BOOKMARK_LAST 1
124 #define BOOKMARK_USER 2
126 #ifndef HAVE_LCD_BITMAP
127 #define BOOKMARK_ICON "\xee\x84\x81\x00"
128 #endif
130 #define PREFERENCES_SIZE (11 + MAX_PATH)
132 /* Out-Of-Bounds test for any pointer to data in the buffer */
133 #define BUFFER_OOB(p) ((p) < buffer || (p) >= buffer_end)
135 /* Does the buffer contain the beginning of the file? */
136 #define BUFFER_BOF() (file_pos==0)
138 /* Does the buffer contain the end of the file? */
139 #define BUFFER_EOF() (file_size-file_pos <= buffer_size)
141 /* Formula for the endpoint address outside of buffer data */
142 #define BUFFER_END() \
143 ((BUFFER_EOF()) ? (file_size-file_pos+buffer) : (buffer+buffer_size))
145 /* Is the entire file being shown in one screen? */
146 #define ONE_SCREEN_FITS_ALL() \
147 (next_screen_ptr==NULL && screen_top_ptr==buffer && BUFFER_BOF())
149 /* Is a scrollbar called for on the current screen? */
150 #define NEED_SCROLLBAR() \
151 ((!(ONE_SCREEN_FITS_ALL())) && (prefs.scrollbar_mode==SB_ON))
153 /* variable button definitions */
155 /* Recorder keys */
156 #if CONFIG_KEYPAD == RECORDER_PAD
157 #define VIEWER_QUIT BUTTON_OFF
158 #define VIEWER_PAGE_UP BUTTON_UP
159 #define VIEWER_PAGE_DOWN BUTTON_DOWN
160 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
161 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
162 #define VIEWER_MENU BUTTON_F1
163 #define VIEWER_AUTOSCROLL BUTTON_PLAY
164 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
165 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
166 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
167 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
168 #define VIEWER_BOOKMARK BUTTON_F2
170 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
171 #define VIEWER_QUIT BUTTON_OFF
172 #define VIEWER_PAGE_UP BUTTON_UP
173 #define VIEWER_PAGE_DOWN BUTTON_DOWN
174 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
175 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
176 #define VIEWER_MENU BUTTON_F1
177 #define VIEWER_AUTOSCROLL BUTTON_SELECT
178 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
179 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
180 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
181 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
182 #define VIEWER_BOOKMARK BUTTON_F2
184 /* Ondio keys */
185 #elif CONFIG_KEYPAD == ONDIO_PAD
186 #define VIEWER_QUIT BUTTON_OFF
187 #define VIEWER_PAGE_UP BUTTON_UP
188 #define VIEWER_PAGE_DOWN BUTTON_DOWN
189 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
190 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
191 #define VIEWER_MENU (BUTTON_MENU|BUTTON_REPEAT)
192 #define VIEWER_AUTOSCROLL_PRE BUTTON_MENU
193 #define VIEWER_AUTOSCROLL (BUTTON_MENU|BUTTON_REL)
194 #define VIEWER_BOOKMARK (BUTTON_MENU|BUTTON_OFF)
196 /* Player keys */
197 #elif CONFIG_KEYPAD == PLAYER_PAD
198 #define VIEWER_QUIT BUTTON_STOP
199 #define VIEWER_PAGE_UP BUTTON_LEFT
200 #define VIEWER_PAGE_DOWN BUTTON_RIGHT
201 #define VIEWER_SCREEN_LEFT (BUTTON_ON|BUTTON_LEFT)
202 #define VIEWER_SCREEN_RIGHT (BUTTON_ON|BUTTON_RIGHT)
203 #define VIEWER_MENU BUTTON_MENU
204 #define VIEWER_AUTOSCROLL BUTTON_PLAY
205 #define VIEWER_BOOKMARK BUTTON_ON
207 /* iRiver H1x0 && H3x0 keys */
208 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
209 (CONFIG_KEYPAD == IRIVER_H300_PAD)
210 #define VIEWER_QUIT BUTTON_OFF
211 #define VIEWER_PAGE_UP BUTTON_UP
212 #define VIEWER_PAGE_DOWN BUTTON_DOWN
213 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
214 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
215 #define VIEWER_MENU BUTTON_MODE
216 #define VIEWER_AUTOSCROLL BUTTON_SELECT
217 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
218 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
219 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
220 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
221 #define VIEWER_BOOKMARK (BUTTON_ON | BUTTON_SELECT)
223 #define VIEWER_RC_QUIT BUTTON_RC_STOP
225 /* iPods */
226 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
227 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
228 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
229 #define VIEWER_QUIT_PRE BUTTON_SELECT
230 #define VIEWER_QUIT (BUTTON_SELECT | BUTTON_MENU)
231 #define VIEWER_PAGE_UP BUTTON_SCROLL_BACK
232 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_FWD
233 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
234 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
235 #define VIEWER_MENU BUTTON_MENU
236 #define VIEWER_AUTOSCROLL BUTTON_PLAY
237 #define VIEWER_BOOKMARK BUTTON_SELECT
239 /* iFP7xx keys */
240 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
241 #define VIEWER_QUIT BUTTON_PLAY
242 #define VIEWER_PAGE_UP BUTTON_UP
243 #define VIEWER_PAGE_DOWN BUTTON_DOWN
244 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
245 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
246 #define VIEWER_MENU BUTTON_MODE
247 #define VIEWER_AUTOSCROLL BUTTON_SELECT
248 #define VIEWER_BOOKMARK (BUTTON_LEFT|BUTTON_SELECT)
250 /* iAudio X5 keys */
251 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
252 #define VIEWER_QUIT BUTTON_POWER
253 #define VIEWER_PAGE_UP BUTTON_UP
254 #define VIEWER_PAGE_DOWN BUTTON_DOWN
255 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
256 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
257 #define VIEWER_MENU BUTTON_SELECT
258 #define VIEWER_AUTOSCROLL BUTTON_PLAY
259 #define VIEWER_BOOKMARK BUTTON_REC
261 /* GIGABEAT keys */
262 #elif CONFIG_KEYPAD == GIGABEAT_PAD
263 #define VIEWER_QUIT BUTTON_POWER
264 #define VIEWER_PAGE_UP BUTTON_UP
265 #define VIEWER_PAGE_DOWN BUTTON_DOWN
266 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
267 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
268 #define VIEWER_MENU BUTTON_MENU
269 #define VIEWER_AUTOSCROLL BUTTON_A
270 #define VIEWER_BOOKMARK BUTTON_SELECT
272 /* Sansa E200 keys */
273 #elif CONFIG_KEYPAD == SANSA_E200_PAD
274 #define VIEWER_QUIT BUTTON_POWER
275 #define VIEWER_PAGE_UP BUTTON_UP
276 #define VIEWER_PAGE_DOWN BUTTON_DOWN
277 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
278 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
279 #define VIEWER_MENU BUTTON_SELECT
280 #define VIEWER_AUTOSCROLL BUTTON_REC
281 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
282 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
283 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
285 /* Sansa Fuze keys */
286 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
287 #define VIEWER_QUIT (BUTTON_HOME|BUTTON_REPEAT)
288 #define VIEWER_PAGE_UP BUTTON_UP
289 #define VIEWER_PAGE_DOWN BUTTON_DOWN
290 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
291 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
292 #define VIEWER_MENU BUTTON_SELECT|BUTTON_REPEAT
293 #define VIEWER_AUTOSCROLL BUTTON_SELECT|BUTTON_DOWN
294 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
295 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
296 #define VIEWER_BOOKMARK BUTTON_SELECT
298 /* Sansa C200 keys */
299 #elif CONFIG_KEYPAD == SANSA_C200_PAD
300 #define VIEWER_QUIT BUTTON_POWER
301 #define VIEWER_PAGE_UP BUTTON_VOL_UP
302 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
303 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
304 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
305 #define VIEWER_MENU BUTTON_SELECT
306 #define VIEWER_AUTOSCROLL BUTTON_REC
307 #define VIEWER_LINE_UP BUTTON_UP
308 #define VIEWER_LINE_DOWN BUTTON_DOWN
309 #define VIEWER_BOOKMARK (BUTTON_DOWN | BUTTON_SELECT)
311 /* Sansa Clip keys */
312 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
313 #define VIEWER_QUIT BUTTON_POWER
314 #define VIEWER_PAGE_UP BUTTON_VOL_UP
315 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
316 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
317 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
318 #define VIEWER_MENU BUTTON_SELECT
319 #define VIEWER_AUTOSCROLL BUTTON_HOME
320 #define VIEWER_LINE_UP BUTTON_UP
321 #define VIEWER_LINE_DOWN BUTTON_DOWN
322 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
324 /* Sansa M200 keys */
325 #elif CONFIG_KEYPAD == SANSA_M200_PAD
326 #define VIEWER_QUIT BUTTON_POWER
327 #define VIEWER_PAGE_UP BUTTON_VOL_UP
328 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
329 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
330 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
331 #define VIEWER_MENU (BUTTON_SELECT | BUTTON_UP)
332 #define VIEWER_AUTOSCROLL (BUTTON_SELECT | BUTTON_REL)
333 #define VIEWER_LINE_UP BUTTON_UP
334 #define VIEWER_LINE_DOWN BUTTON_DOWN
335 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
337 /* iriver H10 keys */
338 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
339 #define VIEWER_QUIT BUTTON_POWER
340 #define VIEWER_PAGE_UP BUTTON_SCROLL_UP
341 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_DOWN
342 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
343 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
344 #define VIEWER_MENU BUTTON_REW
345 #define VIEWER_AUTOSCROLL BUTTON_PLAY
346 #define VIEWER_BOOKMARK BUTTON_FF
348 /*M-Robe 500 keys */
349 #elif CONFIG_KEYPAD == MROBE500_PAD
350 #define VIEWER_QUIT BUTTON_POWER
351 #define VIEWER_PAGE_UP BUTTON_RC_PLAY
352 #define VIEWER_PAGE_DOWN BUTTON_RC_DOWN
353 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
354 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
355 #define VIEWER_MENU BUTTON_RC_HEART
356 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
357 #define VIEWER_BOOKMARK BUTTON_CENTER
359 /*Gigabeat S keys */
360 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
361 #define VIEWER_QUIT BUTTON_BACK
362 #define VIEWER_PAGE_UP BUTTON_PREV
363 #define VIEWER_PAGE_DOWN BUTTON_NEXT
364 #define VIEWER_SCREEN_LEFT (BUTTON_PLAY | BUTTON_LEFT)
365 #define VIEWER_SCREEN_RIGHT (BUTTON_PLAY | BUTTON_RIGHT)
366 #define VIEWER_MENU BUTTON_MENU
367 #define VIEWER_AUTOSCROLL_PRE BUTTON_PLAY
368 #define VIEWER_AUTOSCROLL (BUTTON_PLAY|BUTTON_REL)
369 #define VIEWER_LINE_UP BUTTON_UP
370 #define VIEWER_LINE_DOWN BUTTON_DOWN
371 #define VIEWER_COLUMN_LEFT BUTTON_LEFT
372 #define VIEWER_COLUMN_RIGHT BUTTON_RIGHT
373 #define VIEWER_BOOKMARK BUTTON_SELECT
375 /*M-Robe 100 keys */
376 #elif CONFIG_KEYPAD == MROBE100_PAD
377 #define VIEWER_QUIT BUTTON_POWER
378 #define VIEWER_PAGE_UP BUTTON_UP
379 #define VIEWER_PAGE_DOWN BUTTON_DOWN
380 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
381 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
382 #define VIEWER_MENU BUTTON_MENU
383 #define VIEWER_AUTOSCROLL BUTTON_DISPLAY
384 #define VIEWER_BOOKMARK BUTTON_SELECT
386 /* iAUdio M3 keys */
387 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
388 #define VIEWER_QUIT BUTTON_REC
389 #define VIEWER_PAGE_UP BUTTON_RC_VOL_UP
390 #define VIEWER_PAGE_DOWN BUTTON_RC_VOL_DOWN
391 #define VIEWER_SCREEN_LEFT BUTTON_RC_REW
392 #define VIEWER_SCREEN_RIGHT BUTTON_RC_FF
393 #define VIEWER_MENU BUTTON_RC_MENU
394 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
395 #define VIEWER_RC_QUIT BUTTON_RC_REC
396 #define VIEWER_BOOKMARK BUTTON_RC_PLAY
398 /* Cowon D2 keys */
399 #elif CONFIG_KEYPAD == COWON_D2_PAD
400 #define VIEWER_QUIT BUTTON_POWER
401 #define VIEWER_MENU BUTTON_MENU
402 #define VIEWER_PAGE_UP BUTTON_MINUS
403 #define VIEWER_PAGE_DOWN BUTTON_PLUS
404 #define VIEWER_BOOKMARK (BUTTON_MENU|BUTTON_PLUS)
406 #elif CONFIG_KEYPAD == IAUDIO67_PAD
407 #define VIEWER_QUIT BUTTON_POWER
408 #define VIEWER_PAGE_UP BUTTON_VOLUP
409 #define VIEWER_PAGE_DOWN BUTTON_VOLDOWN
410 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
411 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
412 #define VIEWER_MENU BUTTON_MENU
413 #define VIEWER_AUTOSCROLL BUTTON_PLAY
414 #define VIEWER_RC_QUIT BUTTON_STOP
415 #define VIEWER_BOOKMARK (BUTTON_LEFT|BUTTON_PLAY)
417 /* Creative Zen Vision:M keys */
418 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
419 #define VIEWER_QUIT BUTTON_BACK
420 #define VIEWER_PAGE_UP BUTTON_UP
421 #define VIEWER_PAGE_DOWN BUTTON_DOWN
422 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
423 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
424 #define VIEWER_MENU BUTTON_MENU
425 #define VIEWER_AUTOSCROLL BUTTON_SELECT
426 #define VIEWER_BOOKMARK BUTTON_PLAY
428 /* Philips HDD1630 keys */
429 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
430 #define VIEWER_QUIT BUTTON_POWER
431 #define VIEWER_PAGE_UP BUTTON_UP
432 #define VIEWER_PAGE_DOWN BUTTON_DOWN
433 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
434 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
435 #define VIEWER_MENU BUTTON_MENU
436 #define VIEWER_AUTOSCROLL BUTTON_VIEW
437 #define VIEWER_BOOKMARK BUTTON_SELECT
439 /* Philips SA9200 keys */
440 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
441 #define VIEWER_QUIT BUTTON_POWER
442 #define VIEWER_PAGE_UP BUTTON_UP
443 #define VIEWER_PAGE_DOWN BUTTON_DOWN
444 #define VIEWER_SCREEN_LEFT BUTTON_PREV
445 #define VIEWER_SCREEN_RIGHT BUTTON_NEXT
446 #define VIEWER_MENU BUTTON_MENU
447 #define VIEWER_AUTOSCROLL BUTTON_PLAY
448 #define VIEWER_BOOKMARK BUTTON_RIGHT
450 /* Onda VX747 keys */
451 #elif CONFIG_KEYPAD == ONDAVX747_PAD
452 #define VIEWER_QUIT BUTTON_POWER
453 #define VIEWER_MENU BUTTON_MENU
454 #define VIEWER_BOOKMARK (BUTTON_RIGHT|BUTTON_POWER)
456 /* Onda VX777 keys */
457 #elif CONFIG_KEYPAD == ONDAVX777_PAD
458 #define VIEWER_QUIT BUTTON_POWER
459 #define VIEWER_BOOKMARK (BUTTON_RIGHT|BUTTON_POWER)
461 /* SAMSUNG YH-820 / YH-920 / YH-925 keys */
462 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
463 #define VIEWER_QUIT BUTTON_REC
464 #define VIEWER_PAGE_UP BUTTON_UP
465 #define VIEWER_PAGE_DOWN BUTTON_DOWN
466 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
467 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
468 #define VIEWER_MENU BUTTON_PLAY
469 #define VIEWER_AUTOSCROLL BUTTON_REW
470 #define VIEWER_BOOKMARK BUTTON_FFWD
472 /* Packard Bell Vibe 500 keys */
473 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
474 #define VIEWER_QUIT BUTTON_REC
475 #define VIEWER_PAGE_UP BUTTON_OK
476 #define VIEWER_PAGE_DOWN BUTTON_CANCEL
477 #define VIEWER_LINE_UP BUTTON_UP
478 #define VIEWER_LINE_DOWN BUTTON_DOWN
479 #define VIEWER_SCREEN_LEFT BUTTON_PREV
480 #define VIEWER_SCREEN_RIGHT BUTTON_NEXT
481 #define VIEWER_MENU BUTTON_MENU
482 #define VIEWER_AUTOSCROLL BUTTON_PLAY
483 #define VIEWER_BOOKMARK BUTTON_POWER
485 #else
486 #error No keymap defined!
487 #endif
489 #ifdef HAVE_TOUCHSCREEN
490 #ifdef VIEWER_QUIT
491 #define VIEWER_QUIT2 BUTTON_TOPLEFT
492 #else
493 #define VIEWER_QUIT BUTTON_TOPLEFT
494 #endif
495 #ifdef VIEWER_PAGE_UP
496 #define VIEWER_PAGE_UP2 BUTTON_TOPMIDDLE
497 #else
498 #define VIEWER_PAGE_UP BUTTON_TOPMIDDLE
499 #endif
500 #ifdef VIEWER_PAGE_DOWN
501 #define VIEWER_PAGE_DOWN2 BUTTON_BOTTOMMIDDLE
502 #else
503 #define VIEWER_PAGE_DOWN BUTTON_BOTTOMMIDDLE
504 #endif
505 #ifndef VIEWER_SCREEN_LEFT
506 #define VIEWER_SCREEN_LEFT BUTTON_MIDLEFT
507 #endif
508 #ifndef VIEWER_SCREEN_RIGHT
509 #define VIEWER_SCREEN_RIGHT BUTTON_MIDRIGHT
510 #endif
511 #ifdef VIEWER_MENU
512 #define VIEWER_MENU2 BUTTON_TOPRIGHT
513 #else
514 #define VIEWER_MENU BUTTON_TOPRIGHT
515 #endif
516 #ifndef VIEWER_AUTOSCROLL
517 #define VIEWER_AUTOSCROLL BUTTON_CENTER
518 #endif
519 #endif
521 /* stuff for the bookmarking */
522 struct bookmark_info {
523 long file_position;
524 int page;
525 int line;
526 unsigned char flag;
529 struct preferences {
530 enum {
531 WRAP=0,
532 CHOP,
533 } word_mode;
535 enum {
536 NORMAL=0,
537 JOIN,
538 EXPAND,
539 REFLOW, /* won't be set on charcell LCD, must be last */
540 } line_mode;
542 enum {
543 NARROW=0,
544 WIDE,
545 } view_mode;
547 enum {
548 LEFT=0,
549 RIGHT,
550 } alignment;
552 enum codepages encoding;
554 enum {
555 SB_OFF=0,
556 SB_ON,
557 } scrollbar_mode;
558 bool need_scrollbar;
560 enum {
561 NO_OVERLAP=0,
562 OVERLAP,
563 } page_mode;
565 enum {
566 HD_NONE = 0,
567 HD_PATH,
568 HD_SBAR,
569 HD_BOTH,
570 } header_mode;
572 enum {
573 FT_NONE = 0,
574 FT_PAGE,
575 FT_SBAR,
576 FT_BOTH,
577 } footer_mode;
579 enum {
580 PAGE=0,
581 LINE,
582 } scroll_mode;
584 int autoscroll_speed;
586 unsigned char font[MAX_PATH];
589 enum {
590 VIEWER_FONT_MENU = 0,
591 VIEWER_FONT_TEXT,
594 struct preferences prefs;
595 struct preferences old_prefs;
597 static unsigned char *buffer;
598 static long buffer_size;
599 static long block_size = 0x1000;
600 static unsigned char line_break[] = {0,0x20,9,0xB,0xC,'-'};
601 static int display_columns; /* number of (pixel) columns on the display */
602 static int display_lines; /* number of lines on the display */
603 static int draw_columns; /* number of (pixel) columns available for text */
604 static int par_indent_spaces; /* number of spaces to indent first paragraph */
605 static int fd;
606 static const char *file_name;
607 static long file_size;
608 static long start_position; /* position in the file after the viewer is started */
609 static bool mac_text;
610 static long file_pos; /* Position of the top of the buffer in the file */
611 static long last_file_pos;
612 static unsigned char *buffer_end; /*Set to BUFFER_END() when file_pos changes*/
613 static int max_line_len;
614 static int max_width;
615 static int max_columns;
616 static int cline = 1;
617 static int cpage = 1;
618 static int lpage = 0;
619 static unsigned char *screen_top_ptr;
620 static unsigned char *next_screen_ptr;
621 static unsigned char *next_screen_to_draw_ptr;
622 static unsigned char *next_line_ptr;
623 static unsigned char *last_screen_top_ptr = NULL;
624 #ifdef HAVE_LCD_BITMAP
625 static struct font *pf;
626 static int header_height = 0;
627 static int footer_height = 0;
628 #endif
629 struct bookmark_info bookmarks[MAX_BOOKMARKS];
630 static int bookmark_count;
632 /* UTF-8 BOM */
633 #define BOM "\xef\xbb\xbf"
634 #define BOM_SIZE 3
636 static bool is_bom = false;
638 static int glyph_width(int ch)
640 if (ch == 0)
641 ch = ' ';
643 #ifdef HAVE_LCD_BITMAP
644 return rb->font_get_width(pf, ch);
645 #else
646 return 1;
647 #endif
650 static unsigned char* get_ucs(const unsigned char* str, unsigned short* ch)
652 unsigned char utf8_tmp[6];
653 int count;
655 if (prefs.encoding == UTF_8)
656 return (unsigned char*)rb->utf8decode(str, ch);
658 count = BUFFER_OOB(str+2)? 1:2;
659 rb->iso_decode(str, utf8_tmp, prefs.encoding, count);
660 rb->utf8decode(utf8_tmp, ch);
662 #ifdef HAVE_LCD_BITMAP
663 if (prefs.encoding >= SJIS && *str >= 0x80
664 && !(prefs.encoding == SJIS && *str > 0xA0 && *str < 0xE0))
665 return (unsigned char*)str+2;
666 else
667 #endif
668 return (unsigned char*)str+1;
671 static unsigned char *decode2utf8(const unsigned char *src, unsigned char *dst,
672 int skip_width, int disp_width)
674 unsigned short ch;
675 const unsigned char *oldstr;
676 const unsigned char *str = src;
677 unsigned char *utf8 = dst;
678 int width = 0;
680 while (*str != '\0')
682 oldstr = str;
683 str = get_ucs(oldstr, &ch);
684 width += glyph_width(ch);
685 if (width > skip_width)
687 str = oldstr;
688 break;
691 width = 0;
692 while(*str != '\0')
694 str = get_ucs(str, &ch);
695 width += glyph_width(ch);
696 if (width > disp_width)
697 break;
699 utf8 = rb->utf8encode(ch, utf8);
702 return utf8;
705 static void calc_max_width(void)
707 if (prefs.view_mode == NARROW)
709 max_columns = NARROW_MAX_COLUMNS;
710 max_width = draw_columns;
712 else
714 max_columns = WIDE_MAX_COLUMNS;
715 max_width = 2 * draw_columns;
719 bool done = false;
720 int col = 0;
722 #define ADVANCE_COUNTERS(c) { width += glyph_width(c); k++; }
723 #define LINE_IS_FULL ((k>=max_columns-1) ||( width >= max_width))
724 #define LINE_IS_NOT_FULL ((k<max_columns-1) &&( width < max_width))
725 static unsigned char* crop_at_width(const unsigned char* p)
727 int k,width;
728 unsigned short ch;
729 const unsigned char *oldp = p;
731 k=width=0;
733 while (LINE_IS_NOT_FULL) {
734 oldp = p;
735 if (BUFFER_OOB(p))
736 break;
737 p = get_ucs(p, &ch);
738 ADVANCE_COUNTERS(ch);
741 return (unsigned char*)oldp;
744 static unsigned char* find_first_feed(const unsigned char* p, int size)
746 int i;
748 for (i=0; i < size; i++)
749 if (p[i] == 0)
750 return (unsigned char*) p+i;
752 return NULL;
755 static unsigned char* find_last_feed(const unsigned char* p, int size)
757 int i;
759 for (i=size-1; i>=0; i--)
760 if (p[i] == 0)
761 return (unsigned char*) p+i;
763 return NULL;
766 static unsigned char* find_last_space(const unsigned char* p, int size)
768 int i, j, k;
770 k = (prefs.line_mode==JOIN) || (prefs.line_mode==REFLOW) ? 0:1;
772 if (!BUFFER_OOB(&p[size]))
773 for (j=k; j < ((int) sizeof(line_break)) - 1; j++)
774 if (p[size] == line_break[j])
775 return (unsigned char*) p+size;
777 for (i=size-1; i>=0; i--)
778 for (j=k; j < (int) sizeof(line_break); j++)
780 if (!((p[i] == '-') && (prefs.word_mode == WRAP)))
781 if (p[i] == line_break[j])
782 return (unsigned char*) p+i;
785 return NULL;
788 static unsigned char* find_next_line(const unsigned char* cur_line, bool *is_short)
790 const unsigned char *next_line = NULL;
791 int size, i, j, k, width, search_len, spaces, newlines;
792 bool first_chars;
793 unsigned char c;
795 if (is_short != NULL)
796 *is_short = true;
798 if BUFFER_OOB(cur_line)
799 return NULL;
801 if (prefs.view_mode == WIDE) {
802 search_len = MAX_WIDTH;
804 else { /* prefs.view_mode == NARROW */
805 search_len = crop_at_width(cur_line) - cur_line;
808 size = BUFFER_OOB(cur_line+search_len) ? buffer_end-cur_line : search_len;
810 if ((prefs.line_mode == JOIN) || (prefs.line_mode == REFLOW)) {
811 /* Need to scan ahead and possibly increase search_len and size,
812 or possibly set next_line at second hard return in a row. */
813 next_line = NULL;
814 first_chars=true;
815 for (j=k=width=spaces=newlines=0; ; j++) {
816 if (BUFFER_OOB(cur_line+j))
817 return NULL;
818 if (LINE_IS_FULL) {
819 size = search_len = j;
820 break;
823 c = cur_line[j];
824 switch (c) {
825 case ' ':
826 if (prefs.line_mode == REFLOW) {
827 if (newlines > 0) {
828 size = j;
829 next_line = cur_line + size;
830 return (unsigned char*) next_line;
832 if (j==0) /* i=1 is intentional */
833 for (i=0; i<par_indent_spaces; i++)
834 ADVANCE_COUNTERS(' ');
836 if (!first_chars) spaces++;
837 break;
839 case 0:
840 if (newlines > 0) {
841 size = j;
842 next_line = cur_line + size - spaces;
843 if (next_line != cur_line)
844 return (unsigned char*) next_line;
845 break;
848 newlines++;
849 size += spaces -1;
850 if (BUFFER_OOB(cur_line+size) || size > 2*search_len)
851 return NULL;
852 search_len = size;
853 spaces = first_chars? 0:1;
854 break;
856 default:
857 if (prefs.line_mode==JOIN || newlines>0) {
858 while (spaces) {
859 spaces--;
860 ADVANCE_COUNTERS(' ');
861 if (LINE_IS_FULL) {
862 size = search_len = j;
863 break;
866 newlines=0;
867 } else if (spaces) {
868 /* REFLOW, multiple spaces between words: count only
869 * one. If more are needed, they will be added
870 * while drawing. */
871 search_len = size;
872 spaces=0;
873 ADVANCE_COUNTERS(' ');
874 if (LINE_IS_FULL) {
875 size = search_len = j;
876 break;
879 first_chars = false;
880 ADVANCE_COUNTERS(c);
881 break;
885 else {
886 /* find first hard return */
887 next_line = find_first_feed(cur_line, size);
890 if (next_line == NULL)
891 if (size == search_len) {
892 if (prefs.word_mode == WRAP) /* Find last space */
893 next_line = find_last_space(cur_line, size);
895 if (next_line == NULL)
896 next_line = crop_at_width(cur_line);
897 else
898 if (prefs.word_mode == WRAP)
899 for (i=0;
900 i<WRAP_TRIM && isspace(next_line[0]) && !BUFFER_OOB(next_line);
901 i++)
902 next_line++;
905 if (prefs.line_mode == EXPAND)
906 if (!BUFFER_OOB(next_line)) /* Not Null & not out of bounds */
907 if (next_line[0] == 0)
908 if (next_line != cur_line)
909 return (unsigned char*) next_line;
911 /* If next_line is pointing to a zero, increment it; i.e.,
912 leave the terminator at the end of cur_line. If pointing
913 to a hyphen, increment only if there is room to display
914 the hyphen on current line (won't apply in WIDE mode,
915 since it's guarenteed there won't be room). */
916 if (!BUFFER_OOB(next_line)) /* Not Null & not out of bounds */
917 if (next_line[0] == 0)/* ||
918 (next_line[0] == '-' && next_line-cur_line < draw_columns)) */
919 next_line++;
921 if (BUFFER_OOB(next_line))
923 if (BUFFER_EOF() && next_line != cur_line)
924 return (unsigned char*) next_line;
925 return NULL;
928 if (is_short)
929 *is_short = false;
931 return (unsigned char*) next_line;
934 static unsigned char* find_prev_line(const unsigned char* cur_line)
936 const unsigned char *prev_line = NULL;
937 const unsigned char *p;
939 if BUFFER_OOB(cur_line)
940 return NULL;
942 /* To wrap consistently at the same places, we must
943 start with a known hard return, then work downwards.
944 We can either search backwards for a hard return,
945 or simply start wrapping downwards from top of buffer.
946 If current line is not near top of buffer, this is
947 a file with long lines (paragraphs). We would need to
948 read earlier sectors before we could decide how to
949 properly wrap the lines above the current line, but
950 it probably is not worth the disk access. Instead,
951 start with top of buffer and wrap down from there.
952 This may result in some lines wrapping at different
953 points from where they wrap when scrolling down.
954 If buffer is at top of file, start at top of buffer. */
956 if ((prefs.line_mode == JOIN) || (prefs.line_mode == REFLOW))
957 prev_line = p = NULL;
958 else
959 prev_line = p = find_last_feed(buffer, cur_line-buffer-1);
960 /* Null means no line feeds in buffer above current line. */
962 if (prev_line == NULL)
963 if (BUFFER_BOF() || cur_line - buffer > READ_PREV_ZONE)
964 prev_line = p = buffer;
965 /* (else return NULL and read previous block) */
967 /* Wrap downwards until too far, then use the one before. */
968 while (p != NULL && p < cur_line) {
969 prev_line = p;
970 p = find_next_line(prev_line, NULL);
973 if (BUFFER_OOB(prev_line))
974 return NULL;
976 return (unsigned char*) prev_line;
979 static void check_bom(void)
981 unsigned char bom[BOM_SIZE];
982 off_t orig = rb->lseek(fd, 0, SEEK_CUR);
984 is_bom = false;
986 rb->lseek(fd, 0, SEEK_SET);
988 if (rb->read(fd, bom, BOM_SIZE) == BOM_SIZE)
989 is_bom = !memcmp(bom, BOM, BOM_SIZE);
991 rb->lseek(fd, orig, SEEK_SET);
994 static void fill_buffer(long pos, unsigned char* buf, unsigned size)
996 /* Read from file and preprocess the data */
997 /* To minimize disk access, always read on sector boundaries */
998 unsigned numread, i;
999 bool found_CR = false;
1000 off_t offset = rb->lseek(fd, pos, SEEK_SET);
1002 if (offset == 0 && prefs.encoding == UTF_8 && is_bom)
1003 rb->lseek(fd, BOM_SIZE, SEEK_SET);
1005 numread = rb->read(fd, buf, size);
1006 buf[numread] = 0;
1007 rb->button_clear_queue(); /* clear button queue */
1009 for(i = 0; i < numread; i++) {
1010 switch(buf[i]) {
1011 case '\r':
1012 if (mac_text) {
1013 buf[i] = 0;
1015 else {
1016 buf[i] = ' ';
1017 found_CR = true;
1019 break;
1021 case '\n':
1022 buf[i] = 0;
1023 found_CR = false;
1024 break;
1026 case 0: /* No break between case 0 and default, intentionally */
1027 buf[i] = ' ';
1028 default:
1029 if (found_CR) {
1030 buf[i - 1] = 0;
1031 found_CR = false;
1032 mac_text = true;
1034 break;
1039 static int viewer_find_bookmark(int page, int line)
1041 int i;
1043 for (i = 0; i < bookmark_count; i++)
1045 if (bookmarks[i].page == page && bookmarks[i].line == line)
1046 return i;
1048 return -1;
1051 static int read_and_synch(int direction)
1053 /* Read next (or prev) block, and reposition global pointers. */
1054 /* direction: 1 for down (i.e., further into file), -1 for up */
1055 int move_size, move_vector, offset;
1056 unsigned char *fill_buf;
1058 if (direction == -1) /* up */ {
1059 move_size = SMALL_BLOCK_SIZE;
1060 offset = 0;
1061 fill_buf = TOP_SECTOR;
1062 rb->memcpy(BOTTOM_SECTOR, MID_SECTOR, SMALL_BLOCK_SIZE);
1063 rb->memcpy(MID_SECTOR, TOP_SECTOR, SMALL_BLOCK_SIZE);
1065 else /* down */ {
1066 if (prefs.view_mode == WIDE) {
1067 /* WIDE mode needs more buffer so we have to read smaller blocks */
1068 move_size = SMALL_BLOCK_SIZE;
1069 offset = LARGE_BLOCK_SIZE;
1070 fill_buf = BOTTOM_SECTOR;
1071 rb->memcpy(TOP_SECTOR, MID_SECTOR, SMALL_BLOCK_SIZE);
1072 rb->memcpy(MID_SECTOR, BOTTOM_SECTOR, SMALL_BLOCK_SIZE);
1074 else {
1075 move_size = LARGE_BLOCK_SIZE;
1076 offset = SMALL_BLOCK_SIZE;
1077 fill_buf = MID_SECTOR;
1078 rb->memcpy(TOP_SECTOR, BOTTOM_SECTOR, SMALL_BLOCK_SIZE);
1081 move_vector = direction * move_size;
1082 screen_top_ptr -= move_vector;
1083 file_pos += move_vector;
1084 buffer_end = BUFFER_END(); /* Update whenever file_pos changes */
1085 fill_buffer(file_pos + offset, fill_buf, move_size);
1086 return move_vector;
1089 static void get_next_line_position(unsigned char **line_begin,
1090 unsigned char **line_end,
1091 bool *is_short)
1093 int resynch_move;
1095 *line_begin = *line_end;
1096 *line_end = find_next_line(*line_begin, is_short);
1098 if (*line_end == NULL && !BUFFER_EOF())
1100 resynch_move = read_and_synch(1); /* Read block & move ptrs */
1101 *line_begin -= resynch_move;
1102 if (next_line_ptr > buffer)
1103 next_line_ptr -= resynch_move;
1105 *line_end = find_next_line(*line_begin, is_short);
1109 static void increment_current_line(void)
1111 if (cline < display_lines)
1112 cline++;
1113 else if (cpage < MAX_PAGE)
1115 cpage++;
1116 cline = 1;
1120 static void decrement_current_line(void)
1122 if (cline > 1)
1123 cline--;
1124 else if (cpage > 1)
1126 cpage--;
1127 cline = display_lines;
1131 static void viewer_scroll_up(void)
1133 unsigned char *p;
1135 p = find_prev_line(screen_top_ptr);
1136 if (p == NULL && !BUFFER_BOF()) {
1137 read_and_synch(-1);
1138 p = find_prev_line(screen_top_ptr);
1140 if (p != NULL)
1141 screen_top_ptr = p;
1143 decrement_current_line();
1146 static void viewer_scroll_down(bool autoscroll)
1148 if (cpage == lpage)
1149 return;
1151 if (next_line_ptr != NULL)
1152 screen_top_ptr = next_line_ptr;
1154 if (prefs.scroll_mode == LINE || autoscroll)
1155 increment_current_line();
1158 static void viewer_scroll_to_top_line(void)
1160 int line;
1162 for (line = cline; line > 1; line--)
1163 viewer_scroll_up();
1166 #ifdef HAVE_LCD_BITMAP
1167 static void viewer_scrollbar(void) {
1168 int items, min_shown, max_shown, sb_begin_y, sb_height;
1170 items = (int) file_size; /* (SH1 int is same as long) */
1171 min_shown = (int) file_pos + (screen_top_ptr - buffer);
1173 if (next_screen_ptr == NULL)
1174 max_shown = items;
1175 else
1176 max_shown = min_shown + (next_screen_ptr - screen_top_ptr);
1178 sb_begin_y = header_height;
1179 sb_height = LCD_HEIGHT - header_height - footer_height;
1181 rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN],0, sb_begin_y,
1182 SCROLLBAR_WIDTH-1, sb_height,
1183 items, min_shown, max_shown, VERTICAL);
1185 #endif
1187 #ifdef HAVE_LCD_BITMAP
1188 static void viewer_show_header(void)
1190 if (prefs.header_mode == HD_SBAR || prefs.header_mode == HD_BOTH)
1191 rb->gui_syncstatusbar_draw(rb->statusbars, true);
1193 if (prefs.header_mode == HD_PATH || prefs.header_mode == HD_BOTH)
1194 rb->lcd_putsxy(0, header_height - pf->height, file_name);
1197 static void viewer_show_footer(void)
1199 if (prefs.footer_mode == FT_SBAR || prefs.footer_mode == FT_BOTH)
1200 rb->gui_syncstatusbar_draw(rb->statusbars, true);
1202 if (prefs.footer_mode == FT_PAGE || prefs.footer_mode == FT_BOTH)
1204 unsigned char buf[12];
1206 if (cline == 1)
1207 rb->snprintf(buf, sizeof(buf), "%d", cpage);
1208 else
1209 rb->snprintf(buf, sizeof(buf), "%d - %d", cpage, cpage+1);
1211 rb->lcd_putsxy(0, LCD_HEIGHT - footer_height, buf);
1214 #endif
1216 static void viewer_draw(int col)
1218 int i, j, k, line_len, line_width, spaces, left_col=0;
1219 int width, extra_spaces, indent_spaces, spaces_per_word;
1220 bool multiple_spacing, line_is_short;
1221 unsigned short ch;
1222 unsigned char *str, *oldstr;
1223 unsigned char *line_begin;
1224 unsigned char *line_end;
1225 unsigned char c;
1226 unsigned char scratch_buffer[max_columns + 1];
1227 unsigned char utf8_buffer[max_columns*4 + 1];
1228 unsigned char *endptr;
1230 /* If col==-1 do all calculations but don't display */
1231 if (col != -1) {
1232 #ifdef HAVE_LCD_BITMAP
1233 left_col = prefs.need_scrollbar? SCROLLBAR_WIDTH:0;
1234 #else
1235 left_col = 0;
1236 #endif
1237 rb->lcd_clear_display();
1239 max_line_len = 0;
1240 line_begin = line_end = screen_top_ptr;
1242 for (i = 0; i < display_lines; i++) {
1243 if (BUFFER_OOB(line_end))
1245 if (lpage == cpage)
1246 break; /* Happens after display last line at BUFFER_EOF() */
1248 if (lpage == 0 && cline == 1)
1250 lpage = cpage;
1251 last_screen_top_ptr = screen_top_ptr;
1252 last_file_pos = file_pos;
1256 get_next_line_position(&line_begin, &line_end, &line_is_short);
1257 if (line_end == NULL)
1259 if (BUFFER_OOB(line_begin))
1260 break;
1261 line_end = buffer_end + 1;
1264 line_len = line_end - line_begin;
1266 /* calculate line_len */
1267 str = oldstr = line_begin;
1268 j = -1;
1269 while (str < line_end) {
1270 oldstr = str;
1271 str = crop_at_width(str);
1272 j++;
1274 line_width = j*draw_columns;
1275 while (oldstr < line_end) {
1276 oldstr = get_ucs(oldstr, &ch);
1277 line_width += glyph_width(ch);
1280 if (prefs.line_mode == JOIN) {
1281 if (line_begin[0] == 0) {
1282 line_begin++;
1283 if (prefs.word_mode == CHOP)
1284 line_end++;
1285 else
1286 line_len--;
1288 for (j=k=spaces=0; j < line_len; j++) {
1289 if (k == max_columns)
1290 break;
1292 c = line_begin[j];
1293 switch (c) {
1294 case ' ':
1295 spaces++;
1296 break;
1297 case 0:
1298 spaces = 0;
1299 scratch_buffer[k++] = ' ';
1300 break;
1301 default:
1302 while (spaces) {
1303 spaces--;
1304 scratch_buffer[k++] = ' ';
1305 if (k == max_columns - 1)
1306 break;
1308 scratch_buffer[k++] = c;
1309 break;
1312 if (col != -1) {
1313 scratch_buffer[k] = 0;
1314 endptr = decode2utf8(scratch_buffer, utf8_buffer, col, draw_columns);
1315 *endptr = 0;
1318 else if (prefs.line_mode == REFLOW) {
1319 if (line_begin[0] == 0) {
1320 line_begin++;
1321 if (prefs.word_mode == CHOP)
1322 line_end++;
1323 else
1324 line_len--;
1327 indent_spaces = 0;
1328 if (!line_is_short) {
1329 multiple_spacing = false;
1330 width=spaces=0;
1331 for (str = line_begin; str < line_end; ) {
1332 str = get_ucs(str, &ch);
1333 switch (ch) {
1334 case ' ':
1335 case 0:
1336 if ((str == line_begin) && (prefs.word_mode==WRAP))
1337 /* special case: indent the paragraph,
1338 * don't count spaces */
1339 indent_spaces = par_indent_spaces;
1340 else if (!multiple_spacing)
1341 spaces++;
1342 multiple_spacing = true;
1343 break;
1344 default:
1345 multiple_spacing = false;
1346 width += glyph_width(ch);
1347 break;
1350 if (multiple_spacing) spaces--;
1352 if (spaces) {
1353 /* total number of spaces to insert between words */
1354 extra_spaces = (max_width-width)/glyph_width(' ')
1355 - indent_spaces;
1356 /* number of spaces between each word*/
1357 spaces_per_word = extra_spaces / spaces;
1358 /* number of words with n+1 spaces (to fill up) */
1359 extra_spaces = extra_spaces % spaces;
1360 if (spaces_per_word > 2) { /* too much spacing is awful */
1361 spaces_per_word = 3;
1362 extra_spaces = 0;
1364 } else { /* this doesn't matter much... no spaces anyway */
1365 spaces_per_word = extra_spaces = 0;
1367 } else { /* end of a paragraph: don't fill line */
1368 spaces_per_word = 1;
1369 extra_spaces = 0;
1372 multiple_spacing = false;
1373 for (j=k=spaces=0; j < line_len; j++) {
1374 if (k == max_columns)
1375 break;
1377 c = line_begin[j];
1378 switch (c) {
1379 case ' ':
1380 case 0:
1381 if (j==0 && prefs.word_mode==WRAP) { /* indent paragraph */
1382 for (j=0; j<par_indent_spaces; j++)
1383 scratch_buffer[k++] = ' ';
1384 j=0;
1386 else if (!multiple_spacing) {
1387 for (width = spaces<extra_spaces ? -1:0; width < spaces_per_word; width++)
1388 scratch_buffer[k++] = ' ';
1389 spaces++;
1391 multiple_spacing = true;
1392 break;
1393 default:
1394 scratch_buffer[k++] = c;
1395 multiple_spacing = false;
1396 break;
1399 if (col != -1) {
1400 scratch_buffer[k] = 0;
1401 endptr = decode2utf8(scratch_buffer, utf8_buffer, col, draw_columns);
1402 *endptr = 0;
1405 else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */
1406 if (col != -1)
1407 if (line_width > col) {
1408 str = oldstr = line_begin;
1409 k = col;
1410 width = 0;
1411 while( (width<draw_columns) && (oldstr<line_end) )
1413 oldstr = get_ucs(oldstr, &ch);
1414 if (k > 0) {
1415 k -= glyph_width(ch);
1416 line_begin = oldstr;
1417 } else {
1418 width += glyph_width(ch);
1422 if(prefs.view_mode==WIDE)
1423 endptr = rb->iso_decode(line_begin, utf8_buffer,
1424 prefs.encoding, oldstr-line_begin);
1425 else
1426 endptr = rb->iso_decode(line_begin, utf8_buffer,
1427 prefs.encoding, line_end-line_begin);
1428 *endptr = 0;
1431 if (col != -1 && line_width > col)
1433 int dpage = (cline+i <= display_lines)?cpage:cpage+1;
1434 int dline = cline+i - ((cline+i <= display_lines)?0:display_lines);
1435 bool bflag = (viewer_find_bookmark(dpage, dline) >= 0);
1436 #ifdef HAVE_LCD_BITMAP
1437 int dy = i * pf->height + header_height;
1438 int dx = (prefs.alignment == LEFT) ? left_col : LCD_WIDTH - line_width;
1439 #endif
1440 if (bflag)
1441 #ifdef HAVE_LCD_BITMAP
1443 rb->lcd_set_drawmode(DRMODE_BG|DRMODE_FG);
1444 rb->lcd_fillrect(left_col, dy, LCD_WIDTH, pf->height);
1445 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1447 rb->lcd_putsxy(dx, dy, utf8_buffer);
1448 rb->lcd_set_drawmode(DRMODE_SOLID);
1449 #else
1451 rb->lcd_puts(left_col, i, BOOKMARK_ICON);
1453 rb->lcd_puts(left_col+1, i, utf8_buffer);
1454 #endif
1456 if (line_width > max_line_len)
1457 max_line_len = line_width;
1459 if (i == 0)
1460 next_line_ptr = line_end;
1462 next_screen_ptr = line_end;
1463 if (BUFFER_OOB(next_screen_ptr))
1464 next_screen_ptr = NULL;
1466 #ifdef HAVE_LCD_BITMAP
1467 next_screen_to_draw_ptr = prefs.page_mode==OVERLAP? line_begin: next_screen_ptr;
1469 if (prefs.need_scrollbar)
1470 viewer_scrollbar();
1471 #else
1472 next_screen_to_draw_ptr = next_screen_ptr;
1473 #endif
1475 #ifdef HAVE_LCD_BITMAP
1476 /* show header */
1477 viewer_show_header();
1479 /* show footer */
1480 viewer_show_footer();
1481 #endif
1483 if (col != -1)
1484 rb->lcd_update();
1487 static void viewer_top(void)
1489 /* Read top of file into buffer
1490 and point screen pointer to top */
1491 if (file_pos != 0)
1493 rb->splash(0, "Loading...");
1495 file_pos = 0;
1496 buffer_end = BUFFER_END(); /* Update whenever file_pos changes */
1497 fill_buffer(0, buffer, buffer_size);
1500 screen_top_ptr = buffer;
1501 cpage = 1;
1502 cline = 1;
1505 static void viewer_bottom(void)
1507 unsigned char *line_begin;
1508 unsigned char *line_end;
1510 rb->splash(0, "Loading...");
1512 if (last_screen_top_ptr)
1514 cpage = lpage;
1515 cline = 1;
1516 screen_top_ptr = last_screen_top_ptr;
1517 file_pos = last_file_pos;
1518 fill_buffer(file_pos, buffer, buffer_size);
1519 buffer_end = BUFFER_END();
1520 return;
1523 line_end = screen_top_ptr;
1525 while (!BUFFER_EOF() || !BUFFER_OOB(line_end))
1527 get_next_line_position(&line_begin, &line_end, NULL);
1528 if (line_end == NULL)
1529 break;
1531 increment_current_line();
1532 if (cline == 1)
1533 screen_top_ptr = line_end;
1535 lpage = cpage;
1536 cline = 1;
1537 last_screen_top_ptr = screen_top_ptr;
1538 last_file_pos = file_pos;
1539 buffer_end = BUFFER_END();
1542 #ifdef HAVE_LCD_BITMAP
1543 static void init_need_scrollbar(void) {
1544 /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
1545 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
1546 viewer_draw(-1);
1547 prefs.need_scrollbar = NEED_SCROLLBAR();
1548 draw_columns = prefs.need_scrollbar? display_columns-SCROLLBAR_WIDTH : display_columns;
1549 par_indent_spaces = draw_columns/(5*glyph_width(' '));
1550 calc_max_width();
1553 static void init_header_and_footer(void)
1555 header_height = 0;
1556 footer_height = 0;
1557 if (rb->global_settings->statusbar == STATUSBAR_TOP)
1559 if (prefs.header_mode == HD_SBAR || prefs.header_mode == HD_BOTH)
1560 header_height = STATUSBAR_HEIGHT;
1562 if (prefs.footer_mode == FT_SBAR)
1563 prefs.footer_mode = FT_NONE;
1564 else if (prefs.footer_mode == FT_BOTH)
1565 prefs.footer_mode = FT_PAGE;
1567 else if (rb->global_settings->statusbar == STATUSBAR_BOTTOM)
1569 if (prefs.footer_mode == FT_SBAR || prefs.footer_mode == FT_BOTH)
1570 footer_height = STATUSBAR_HEIGHT;
1572 if (prefs.header_mode == HD_SBAR)
1573 prefs.header_mode = HD_NONE;
1574 else if (prefs.header_mode == HD_BOTH)
1575 prefs.header_mode = HD_PATH;
1577 else /* STATUSBAR_OFF || STATUSBAR_CUSTOM */
1579 if (prefs.header_mode == HD_SBAR)
1580 prefs.header_mode = HD_NONE;
1581 else if (prefs.header_mode == HD_BOTH)
1582 prefs.header_mode = HD_PATH;
1584 if (prefs.footer_mode == FT_SBAR)
1585 prefs.footer_mode = FT_NONE;
1586 else if (prefs.footer_mode == FT_BOTH)
1587 prefs.footer_mode = FT_PAGE;
1590 if (prefs.header_mode == HD_NONE || prefs.header_mode == HD_PATH ||
1591 prefs.footer_mode == FT_NONE || prefs.footer_mode == FT_PAGE)
1592 rb->gui_syncstatusbar_draw(rb->statusbars, false);
1594 if (prefs.header_mode == HD_PATH || prefs.header_mode == HD_BOTH)
1595 header_height += pf->height;
1596 if (prefs.footer_mode == FT_PAGE || prefs.footer_mode == FT_BOTH)
1597 footer_height += pf->height;
1599 display_lines = (LCD_HEIGHT - header_height - footer_height) / pf->height;
1601 lpage = 0;
1602 last_file_pos = 0;
1603 last_screen_top_ptr = NULL;
1606 static void change_font(unsigned char *font)
1608 unsigned char buf[MAX_PATH];
1610 if (font == NULL || *font == '\0')
1611 return;
1613 rb->snprintf(buf, MAX_PATH, "%s/%s.fnt", FONT_DIR, font);
1614 if (rb->font_load(NULL, buf) < 0)
1615 rb->splash(HZ/2, "font load failed.");
1617 #endif
1619 static bool viewer_init(void)
1621 #ifdef HAVE_LCD_BITMAP
1622 /* initialize fonts */
1623 pf = rb->font_get(FONT_UI);
1624 draw_columns = display_columns = LCD_WIDTH;
1625 #else
1626 /* REAL fixed pitch :) all chars use up 1 cell */
1627 display_lines = 2;
1628 draw_columns = display_columns = 11;
1629 par_indent_spaces = 2;
1630 #endif
1632 fd = rb->open(file_name, O_RDONLY);
1633 if (fd < 0)
1634 return false;
1636 /* Init mac_text value used in processing buffer */
1637 mac_text = false;
1639 return true;
1642 /* When a file is UTF-8 file with BOM, if prefs.encoding is UTF-8,
1643 * then file size decreases only BOM_SIZE.
1645 static void get_filesize(void)
1647 file_size = rb->filesize(fd);
1648 if (file_size == -1)
1649 return;
1651 if (prefs.encoding == UTF_8 && is_bom)
1652 file_size -= BOM_SIZE;
1655 static int bm_comp(const void *a, const void *b)
1657 struct bookmark_info *pa;
1658 struct bookmark_info *pb;
1660 pa = (struct bookmark_info*)a;
1661 pb = (struct bookmark_info*)b;
1663 if (pa->page != pb->page)
1664 return pa->page - pb->page;
1666 return pa->line - pb->line;
1669 static void viewer_add_bookmark(void)
1671 if (bookmark_count >= MAX_BOOKMARKS-1)
1672 return;
1674 bookmarks[bookmark_count].file_position
1675 = file_pos + screen_top_ptr - buffer;
1676 bookmarks[bookmark_count].page = cpage;
1677 bookmarks[bookmark_count].line = cline;
1678 bookmarks[bookmark_count].flag = BOOKMARK_USER;
1679 bookmark_count++;
1682 static int viewer_add_last_read_bookmark(void)
1684 int i;
1686 i = viewer_find_bookmark(cpage, cline);
1687 if (i >= 0)
1688 bookmarks[i].flag |= BOOKMARK_LAST;
1689 else
1691 viewer_add_bookmark();
1692 i = bookmark_count-1;
1693 bookmarks[i].flag = BOOKMARK_LAST;
1695 return i;
1698 static void viewer_remove_bookmark(int i)
1700 int j;
1702 if (i < 0 || i >= bookmark_count)
1703 return;
1705 for (j = i+1; j < bookmark_count; j++)
1706 rb->memcpy(&bookmarks[j-1], &bookmarks[j],
1707 sizeof(struct bookmark_info));
1709 bookmark_count--;
1712 static void viewer_remove_last_read_bookmark(void)
1714 int i, j;
1716 for (i = 0; i < bookmark_count; i++)
1718 if (bookmarks[i].flag & BOOKMARK_LAST)
1720 if (bookmarks[i].flag == BOOKMARK_LAST)
1722 for (j = i+1; j < bookmark_count; j++)
1723 rb->memcpy(&bookmarks[j-1], &bookmarks[j],
1724 sizeof(struct bookmark_info));
1726 bookmark_count--;
1728 else
1729 bookmarks[i].flag = BOOKMARK_USER;
1730 break;
1735 static int viewer_get_last_read_bookmark(void)
1737 int i;
1739 for (i = 0; i < bookmark_count; i++)
1741 if (bookmarks[i].flag & BOOKMARK_LAST)
1742 return i;
1744 return -1;
1747 static void viewer_select_bookmark(int initval)
1749 int i;
1750 int ipage = 0;
1751 int iline = 0;
1752 int screen_pos;
1753 int screen_top;
1754 int selected = -1;
1756 struct opt_items items[bookmark_count];
1757 unsigned char names[bookmark_count][38];
1759 if (initval >= 0 && initval < bookmark_count)
1761 ipage = bookmarks[initval].page;
1762 iline = bookmarks[initval].line;
1765 rb->qsort(bookmarks, bookmark_count, sizeof(struct bookmark_info),
1766 bm_comp);
1768 for (i = 0; i < bookmark_count; i++)
1770 rb->snprintf(names[i], sizeof(names[0]),
1771 #if CONFIG_KEYPAD != PLAYER_PAD
1772 "%sPage: %d Line: %d",
1773 #else
1774 "%sP:%d L:%d",
1775 #endif
1776 (bookmarks[i].flag&BOOKMARK_LAST)? "*":" ",
1777 bookmarks[i].page,
1778 bookmarks[i].line);
1779 items[i].string = names[i];
1780 items[i].voice_id = -1;
1781 if (selected < 0 && bookmarks[i].page == ipage && bookmarks[i].line == iline)
1782 selected = i;
1785 rb->set_option("Select bookmark", &selected, INT, items,
1786 sizeof(items) / sizeof(items[0]), NULL);
1788 if (selected < 0 || selected >= bookmark_count)
1790 if (initval < 0 || (selected = viewer_get_last_read_bookmark()) < 0)
1792 if (initval < 0)
1793 rb->splash(HZ, "Start the first page.");
1794 file_pos = 0;
1795 screen_top_ptr = buffer;
1796 cpage = 1;
1797 cline = 1;
1798 buffer_end = BUFFER_END();
1799 return;
1803 screen_pos = bookmarks[selected].file_position;
1804 screen_top = screen_pos % buffer_size;
1805 file_pos = screen_pos - screen_top;
1806 screen_top_ptr = buffer + screen_top;
1807 cpage = bookmarks[selected].page;
1808 cline = bookmarks[selected].line;
1809 buffer_end = BUFFER_END();
1812 static void viewer_default_preferences(void)
1814 prefs.word_mode = WRAP;
1815 prefs.line_mode = NORMAL;
1816 prefs.view_mode = NARROW;
1817 prefs.alignment = LEFT;
1818 prefs.scroll_mode = PAGE;
1819 prefs.page_mode = NO_OVERLAP;
1820 prefs.scrollbar_mode = SB_OFF;
1821 rb->memset(prefs.font, 0, MAX_PATH);
1822 #ifdef HAVE_LCD_BITMAP
1823 prefs.header_mode = HD_BOTH;
1824 prefs.footer_mode = FT_BOTH;
1825 rb->snprintf(prefs.font, MAX_PATH, "%s", rb->global_settings->font_file);
1826 #else
1827 prefs.header_mode = HD_NONE;
1828 prefs.footer_mode = FT_NONE;
1829 #endif
1830 prefs.autoscroll_speed = 1;
1831 /* Set codepage to system default */
1832 prefs.encoding = rb->global_settings->default_codepage;
1835 static bool viewer_read_preferences(int pfd)
1837 unsigned char buf[PREFERENCES_SIZE];
1838 unsigned char *p = buf;
1840 if (rb->read(pfd, buf, sizeof(buf)) != sizeof(buf))
1841 return false;
1843 prefs.word_mode = *p++;
1844 prefs.line_mode = *p++;
1845 prefs.view_mode = *p++;
1846 prefs.alignment = *p++;
1847 prefs.encoding = *p++;
1848 prefs.scrollbar_mode = *p++;
1849 prefs.need_scrollbar = *p++;
1850 prefs.page_mode = *p++;
1851 prefs.header_mode = *p++;
1852 prefs.footer_mode = *p++;
1853 prefs.scroll_mode = *p++;
1854 prefs.autoscroll_speed = *p++;
1855 rb->memcpy(prefs.font, p, MAX_PATH);
1857 return true;
1860 static bool viewer_write_preferences(int pfd)
1862 unsigned char buf[PREFERENCES_SIZE];
1863 unsigned char *p = buf;
1865 *p++ = prefs.word_mode;
1866 *p++ = prefs.line_mode;
1867 *p++ = prefs.view_mode;
1868 *p++ = prefs.alignment;
1869 *p++ = prefs.encoding;
1870 *p++ = prefs.scrollbar_mode;
1871 *p++ = prefs.need_scrollbar;
1872 *p++ = prefs.page_mode;
1873 *p++ = prefs.header_mode;
1874 *p++ = prefs.footer_mode;
1875 *p++ = prefs.scroll_mode;
1876 *p++ = prefs.autoscroll_speed;
1877 rb->memcpy(p, prefs.font, MAX_PATH);
1879 return (rb->write(pfd, buf, sizeof(buf)) == sizeof(buf));
1882 static bool viewer_read_bookmark_info(int bfd, struct bookmark_info *b)
1884 unsigned char buf[BOOKMARK_SIZE];
1886 if (rb->read(bfd, buf, sizeof(buf)) != sizeof(buf))
1887 return false;
1889 b->file_position = (buf[0] << 24)|(buf[1] << 16)|(buf[2] << 8)|buf[3];
1890 b->page = (buf[4] << 8)|buf[5];
1891 b->line = buf[6];
1892 b->flag = buf[7];
1894 return true;
1897 static bool viewer_read_bookmark_infos(int bfd)
1899 unsigned char c;
1900 int i;
1902 if (rb->read(bfd, &c, 1) != 1)
1904 bookmark_count = 0;
1905 return false;
1908 bookmark_count = c;
1909 if (bookmark_count > MAX_BOOKMARKS)
1910 bookmark_count = MAX_BOOKMARKS;
1912 for (i = 0; i < bookmark_count; i++)
1914 if (!viewer_read_bookmark_info(bfd, &bookmarks[i]))
1916 bookmark_count = i;
1917 return false;
1920 return true;
1923 static bool viewer_write_bookmark_info(int bfd, struct bookmark_info *b)
1925 unsigned char buf[BOOKMARK_SIZE];
1926 unsigned char *p = buf;
1927 unsigned long ul;
1929 ul = b->file_position;
1930 *p++ = ul >> 24;
1931 *p++ = ul >> 16;
1932 *p++ = ul >> 8;
1933 *p++ = ul;
1935 ul = b->page;
1936 *p++ = ul >> 8;
1937 *p++ = ul;
1939 *p++ = b->line;
1940 *p = b->flag;
1942 return (rb->write(bfd, buf, sizeof(buf)) == sizeof(buf));
1945 static bool viewer_write_bookmark_infos(int bfd)
1947 unsigned char c = bookmark_count;
1948 int i;
1950 if (rb->write(bfd, &c, 1) != 1)
1951 return false;
1953 for (i = 0; i < bookmark_count; i++)
1955 if (!viewer_write_bookmark_info(bfd, &bookmarks[i]))
1956 return false;
1959 return true;
1962 static bool viewer_load_global_settings(void)
1964 unsigned buf[GLOBAL_SETTINGS_H_SIZE];
1965 int sfd = rb->open(GLOBAL_SETTINGS_FILE, O_RDONLY);
1967 if (sfd < 0)
1968 return false;
1970 if ((rb->read(sfd, buf, GLOBAL_SETTINGS_H_SIZE) != GLOBAL_SETTINGS_H_SIZE) ||
1971 rb->memcmp(buf, GLOBAL_SETTINGS_HEADER, GLOBAL_SETTINGS_H_SIZE) ||
1972 !viewer_read_preferences(sfd))
1974 rb->close(sfd);
1975 return false;
1977 rb->close(sfd);
1978 return true;
1981 static bool viewer_save_global_settings(void)
1983 int sfd = rb->open(GLOBAL_SETTINGS_TMP_FILE, O_WRONLY|O_CREAT|O_TRUNC);
1985 if (sfd < 0)
1986 return false;
1988 if (rb->write(sfd, &GLOBAL_SETTINGS_HEADER, GLOBAL_SETTINGS_H_SIZE)
1989 != GLOBAL_SETTINGS_H_SIZE ||
1990 !viewer_write_preferences(sfd))
1992 rb->close(sfd);
1993 rb->remove(GLOBAL_SETTINGS_TMP_FILE);
1994 return false;
1996 rb->close(sfd);
1997 rb->remove(GLOBAL_SETTINGS_FILE);
1998 rb->rename(GLOBAL_SETTINGS_TMP_FILE, GLOBAL_SETTINGS_FILE);
1999 return true;
2002 static void viewer_load_settings(void)
2004 unsigned char buf[MAX_PATH+2];
2005 unsigned int fcount;
2006 unsigned int i;
2007 bool res = false;
2008 int sfd;
2009 unsigned int size;
2011 sfd = rb->open(SETTINGS_FILE, O_RDONLY);
2012 if (sfd < 0)
2013 goto read_end;
2015 if ((rb->read(sfd, buf, SETTINGS_H_SIZE+2) != SETTINGS_H_SIZE+2) ||
2016 rb->memcmp(buf, SETTINGS_HEADER, SETTINGS_H_SIZE))
2018 /* illegal setting file */
2019 rb->close(sfd);
2021 if (rb->file_exists(SETTINGS_FILE))
2022 rb->remove(SETTINGS_FILE);
2024 goto read_end;
2027 fcount = (buf[SETTINGS_H_SIZE] << 8) | buf[SETTINGS_H_SIZE+1];
2028 for (i = 0; i < fcount; i++)
2030 if (rb->read(sfd, buf, MAX_PATH+2) != MAX_PATH+2)
2031 break;
2033 size = (buf[MAX_PATH] << 8) | buf[MAX_PATH+1];
2034 if (rb->strcmp(buf, file_name))
2036 if (rb->lseek(sfd, size, SEEK_CUR) < 0)
2037 break;
2038 continue;
2040 if (!viewer_read_preferences(sfd))
2041 break;
2043 res = viewer_read_bookmark_infos(sfd);
2044 break;
2047 rb->close(sfd);
2049 read_end:
2050 if (!res)
2052 /* load global settings */
2053 if (!viewer_load_global_settings())
2054 viewer_default_preferences();
2056 file_pos = 0;
2057 screen_top_ptr = buffer;
2058 cpage = 1;
2059 cline = 1;
2060 bookmark_count = 0;
2063 rb->memcpy(&old_prefs, &prefs, sizeof(struct preferences));
2064 calc_max_width();
2066 if (bookmark_count > 1)
2067 viewer_select_bookmark(-1);
2068 else if (bookmark_count == 1)
2070 int screen_pos;
2071 int screen_top;
2073 screen_pos = bookmarks[0].file_position;
2074 screen_top = screen_pos % buffer_size;
2075 file_pos = screen_pos - screen_top;
2076 screen_top_ptr = buffer + screen_top;
2077 cpage = bookmarks[0].page;
2078 cline = bookmarks[0].line;
2081 viewer_remove_last_read_bookmark();
2083 check_bom();
2084 get_filesize();
2086 buffer_end = BUFFER_END(); /* Update whenever file_pos changes */
2088 if (BUFFER_OOB(screen_top_ptr))
2089 screen_top_ptr = buffer;
2091 fill_buffer(file_pos, buffer, buffer_size);
2092 if (prefs.scroll_mode == PAGE && cline > 1)
2093 viewer_scroll_to_top_line();
2095 /* remember the current position */
2096 start_position = file_pos + screen_top_ptr - buffer;
2098 #ifdef HAVE_LCD_BITMAP
2099 if (rb->strcmp(prefs.font, rb->global_settings->font_file))
2100 change_font(prefs.font);
2102 init_need_scrollbar();
2103 init_header_and_footer();
2104 #endif
2107 static bool copy_bookmark_file(int sfd, int dfd, off_t start, off_t size)
2109 off_t rsize;
2111 if (rb->lseek(sfd, start, SEEK_SET) < 0)
2112 return false;
2114 while (size > 0)
2116 if (size > buffer_size)
2117 rsize = buffer_size;
2118 else
2119 rsize = size;
2120 size -= rsize;
2122 if (rb->read(sfd, buffer, rsize) != rsize ||
2123 rb->write(dfd, buffer, rsize) != rsize)
2124 return false;
2126 return true;
2129 static bool viewer_save_settings(void)
2131 unsigned char buf[MAX_PATH+2];
2132 unsigned int fcount = 0;
2133 unsigned int i;
2134 int idx;
2135 int ofd;
2136 int tfd;
2137 off_t first_copy_size = 0;
2138 off_t second_copy_start_pos = 0;
2139 off_t size;
2141 /* add reading page to bookmarks */
2142 idx = viewer_find_bookmark(cpage, cline);
2143 if (idx >= 0)
2144 bookmarks[idx].flag |= BOOKMARK_LAST;
2145 else
2147 viewer_add_bookmark();
2148 bookmarks[bookmark_count-1].flag = BOOKMARK_LAST;
2151 tfd = rb->open(SETTINGS_TMP_FILE, O_WRONLY|O_CREAT|O_TRUNC);
2152 if (tfd < 0)
2153 return false;
2155 ofd = rb->open(SETTINGS_FILE, O_RDWR);
2156 if (ofd >= 0)
2158 if ((rb->read(ofd, buf, SETTINGS_H_SIZE+2) != SETTINGS_H_SIZE+2) ||
2159 rb->memcmp(buf, SETTINGS_HEADER, SETTINGS_H_SIZE))
2161 rb->close(ofd);
2162 goto save_err;
2164 fcount = (buf[SETTINGS_H_SIZE] << 8) | buf[SETTINGS_H_SIZE+1];
2166 for (i = 0; i < fcount; i++)
2168 if (rb->read(ofd, buf, MAX_PATH+2) != MAX_PATH+2)
2170 rb->close(ofd);
2171 goto save_err;
2173 size = (buf[MAX_PATH] << 8) | buf[MAX_PATH+1];
2174 if (rb->strcmp(buf, file_name))
2176 if (rb->lseek(ofd, size, SEEK_CUR) < 0)
2178 rb->close(ofd);
2179 goto save_err;
2182 else
2184 first_copy_size = rb->lseek(ofd, 0, SEEK_CUR);
2185 if (first_copy_size < 0)
2187 rb->close(ofd);
2188 goto save_err;
2190 second_copy_start_pos = first_copy_size + size;
2191 first_copy_size -= MAX_PATH+2;
2192 fcount--;
2193 break;
2196 if (first_copy_size == 0)
2197 first_copy_size = rb->filesize(ofd);
2199 if (!copy_bookmark_file(ofd, tfd, 0, first_copy_size))
2201 rb->close(ofd);
2202 goto save_err;
2204 if (second_copy_start_pos > 0)
2206 if (!copy_bookmark_file(ofd, tfd, second_copy_start_pos,
2207 rb->filesize(ofd) - second_copy_start_pos))
2209 rb->close(ofd);
2210 goto save_err;
2213 rb->close(ofd);
2215 else
2217 rb->memcpy(buf, SETTINGS_HEADER, SETTINGS_H_SIZE);
2218 buf[SETTINGS_H_SIZE] = 0;
2219 buf[SETTINGS_H_SIZE+1] = 0;
2220 if (rb->write(tfd, buf, SETTINGS_H_SIZE+2) != SETTINGS_H_SIZE+2)
2221 goto save_err;
2224 /* copy to current read file's bookmarks */
2225 rb->memset(buf, 0, MAX_PATH);
2226 rb->snprintf(buf, MAX_PATH, "%s", file_name);
2228 size = PREFERENCES_SIZE + bookmark_count * BOOKMARK_SIZE + 1;
2229 buf[MAX_PATH] = size >> 8;
2230 buf[MAX_PATH+1] = size;
2232 if (rb->write(tfd, buf, MAX_PATH+2) != MAX_PATH+2)
2233 goto save_err;
2235 if (!viewer_write_preferences(tfd))
2236 goto save_err;
2238 if (!viewer_write_bookmark_infos(tfd))
2239 goto save_err;
2241 if (rb->lseek(tfd, SETTINGS_H_SIZE, SEEK_SET) < 0)
2242 goto save_err;
2244 fcount++;
2245 buf[0] = fcount >> 8;
2246 buf[1] = fcount;
2248 if (rb->write(tfd, buf, 2) != 2)
2249 goto save_err;
2251 rb->close(tfd);
2253 rb->remove(SETTINGS_FILE);
2254 rb->rename(SETTINGS_TMP_FILE, SETTINGS_FILE);
2256 return true;
2258 save_err:
2259 rb->close(tfd);
2260 rb->remove(SETTINGS_TMP_FILE);
2261 return false;
2264 static void viewer_exit(void *parameter)
2266 (void)parameter;
2268 /* save preference and bookmarks */
2269 if (!viewer_save_settings())
2270 rb->splash(HZ, "Can't save preference and bookmarks.");
2272 rb->close(fd);
2273 #ifdef HAVE_LCD_BITMAP
2274 if (rb->strcmp(prefs.font, rb->global_settings->font_file))
2275 change_font(rb->global_settings->font_file);
2276 #endif
2279 static void calc_page(void)
2281 int i;
2282 unsigned char *line_begin;
2283 unsigned char *line_end;
2284 off_t sfp;
2285 unsigned char *sstp;
2287 rb->splash(0, "Calculating page/line number...");
2289 /* add reading page to bookmarks */
2290 viewer_add_last_read_bookmark();
2292 rb->qsort(bookmarks, bookmark_count, sizeof(struct bookmark_info),
2293 bm_comp);
2295 cpage = 1;
2296 cline = 1;
2297 file_pos = 0;
2298 screen_top_ptr = buffer;
2299 buffer_end = BUFFER_END();
2301 fill_buffer(file_pos, buffer, buffer_size);
2302 line_end = line_begin = buffer;
2304 for (i = 0; i < bookmark_count; i++)
2306 sfp = bookmarks[i].file_position;
2307 sstp = buffer;
2309 while ((line_begin > sstp || sstp >= line_end) ||
2310 (file_pos > sfp || sfp >= file_pos + BUFFER_END() - buffer))
2312 get_next_line_position(&line_begin, &line_end, NULL);
2313 if (line_end == NULL)
2314 break;
2316 next_line_ptr = line_end;
2318 if (sstp == buffer &&
2319 file_pos <= sfp && sfp < file_pos + BUFFER_END() - buffer)
2320 sstp = sfp - file_pos + buffer;
2322 increment_current_line();
2325 decrement_current_line();
2326 bookmarks[i].page = cpage;
2327 bookmarks[i].line = cline;
2328 bookmarks[i].file_position = file_pos + (line_begin - buffer);
2329 increment_current_line();
2332 /* remove reading page's bookmark */
2333 for (i = 0; i < bookmark_count; i++)
2335 if (bookmarks[i].flag & BOOKMARK_LAST)
2337 int screen_pos;
2338 int screen_top;
2340 screen_pos = bookmarks[i].file_position;
2341 screen_top = screen_pos % buffer_size;
2342 file_pos = screen_pos - screen_top;
2343 screen_top_ptr = buffer + screen_top;
2345 cpage = bookmarks[i].page;
2346 cline = bookmarks[i].line;
2347 bookmarks[i].flag ^= BOOKMARK_LAST;
2348 buffer_end = BUFFER_END();
2350 fill_buffer(file_pos, buffer, buffer_size);
2352 if (bookmarks[i].flag == 0)
2353 viewer_remove_bookmark(i);
2355 if (prefs.scroll_mode == PAGE && cline > 1)
2356 viewer_scroll_to_top_line();
2357 break;
2362 static int col_limit(int col)
2364 if (col < 0)
2365 col = 0;
2366 else
2367 if (col >= max_width)
2368 col = max_width - draw_columns;
2370 return col;
2373 /* settings helper functions */
2375 static bool encoding_setting(void)
2377 static struct opt_items names[NUM_CODEPAGES];
2378 int idx;
2379 bool res;
2380 enum codepages oldenc = prefs.encoding;
2382 for (idx = 0; idx < NUM_CODEPAGES; idx++)
2384 names[idx].string = rb->get_codepage_name(idx);
2385 names[idx].voice_id = -1;
2388 res = rb->set_option("Encoding", &prefs.encoding, INT, names,
2389 sizeof(names) / sizeof(names[0]), NULL);
2391 /* When prefs.encoding changes into UTF-8 or changes from UTF-8,
2392 * filesize (file_size) might change.
2393 * In addition, if prefs.encoding is UTF-8, then BOM does not read.
2395 if (oldenc != prefs.encoding && (oldenc == UTF_8 || prefs.encoding == UTF_8))
2397 check_bom();
2398 get_filesize();
2399 fill_buffer(file_pos, buffer, buffer_size);
2402 return res;
2405 static bool word_wrap_setting(void)
2407 static const struct opt_items names[] = {
2408 {"On", -1},
2409 {"Off (Chop Words)", -1},
2412 return rb->set_option("Word Wrap", &prefs.word_mode, INT,
2413 names, 2, NULL);
2416 static bool line_mode_setting(void)
2418 static const struct opt_items names[] = {
2419 {"Normal", -1},
2420 {"Join Lines", -1},
2421 {"Expand Lines", -1},
2422 #ifdef HAVE_LCD_BITMAP
2423 {"Reflow Lines", -1},
2424 #endif
2427 return rb->set_option("Line Mode", &prefs.line_mode, INT, names,
2428 sizeof(names) / sizeof(names[0]), NULL);
2431 static bool view_mode_setting(void)
2433 static const struct opt_items names[] = {
2434 {"No (Narrow)", -1},
2435 {"Yes", -1},
2437 bool ret;
2438 ret = rb->set_option("Wide View", &prefs.view_mode, INT,
2439 names , 2, NULL);
2440 if (prefs.view_mode == NARROW)
2441 col = 0;
2442 calc_max_width();
2443 return ret;
2446 static bool scroll_mode_setting(void)
2448 static const struct opt_items names[] = {
2449 {"Scroll by Page", -1},
2450 {"Scroll by Line", -1},
2453 return rb->set_option("Scroll Mode", &prefs.scroll_mode, INT,
2454 names, 2, NULL);
2457 #ifdef HAVE_LCD_BITMAP
2458 static bool page_mode_setting(void)
2460 static const struct opt_items names[] = {
2461 {"No", -1},
2462 {"Yes", -1},
2465 return rb->set_option("Overlap Pages", &prefs.page_mode, INT,
2466 names, 2, NULL);
2469 static bool scrollbar_setting(void)
2471 static const struct opt_items names[] = {
2472 {"Off", -1},
2473 {"On", -1}
2476 return rb->set_option("Show Scrollbar", &prefs.scrollbar_mode, INT,
2477 names, 2, NULL);
2480 static bool header_setting(void)
2482 int len = (rb->global_settings->statusbar == STATUSBAR_TOP)? 4 : 2;
2483 struct opt_items names[len];
2485 names[0].string = "None";
2486 names[0].voice_id = -1;
2487 names[1].string = "File path";
2488 names[1].voice_id = -1;
2490 if (rb->global_settings->statusbar == STATUSBAR_TOP)
2492 names[2].string = "Status bar";
2493 names[2].voice_id = -1;
2494 names[3].string = "Both";
2495 names[3].voice_id = -1;
2498 return rb->set_option("Show Header", &prefs.header_mode, INT,
2499 names, len, NULL);
2502 static bool footer_setting(void)
2504 int len = (rb->global_settings->statusbar == STATUSBAR_BOTTOM)? 4 : 2;
2505 struct opt_items names[len];
2507 names[0].string = "None";
2508 names[0].voice_id = -1;
2509 names[1].string = "Page Num";
2510 names[1].voice_id = -1;
2512 if (rb->global_settings->statusbar == STATUSBAR_BOTTOM)
2514 names[2].string = "Status bar";
2515 names[2].voice_id = -1;
2516 names[3].string = "Both";
2517 names[3].voice_id = -1;
2520 return rb->set_option("Show Footer", &prefs.footer_mode, INT,
2521 names, len, NULL);
2524 static int font_comp(const void *a, const void *b)
2526 struct opt_items *pa;
2527 struct opt_items *pb;
2529 pa = (struct opt_items *)a;
2530 pb = (struct opt_items *)b;
2532 return rb->strcmp(pa->string, pb->string);
2535 static bool font_setting(void)
2537 int count = 0;
2538 DIR *dir;
2539 struct dirent *entry;
2540 int i = 0;
2541 int len;
2542 int new_font = 0;
2543 int old_font;
2544 bool res;
2545 int size = 0;
2547 dir = rb->opendir(FONT_DIR);
2548 if (!dir)
2550 rb->splash(HZ/2, "font dir does not access.");
2551 return false;
2554 while (1)
2556 entry = rb->readdir(dir);
2558 if (entry == NULL)
2559 break;
2561 len = rb->strlen(entry->d_name);
2562 if (len < 4 || rb->strcmp(entry->d_name + len-4, ".fnt"))
2563 continue;
2564 size += len-3;
2565 count++;
2567 rb->closedir(dir);
2569 struct opt_items names[count];
2570 unsigned char font_names[size];
2571 unsigned char *p = font_names;
2573 dir = rb->opendir(FONT_DIR);
2574 if (!dir)
2576 rb->splash(HZ/2, "font dir does not access.");
2577 return false;
2580 while (1)
2582 entry = rb->readdir(dir);
2584 if (entry == NULL)
2585 break;
2587 len = rb->strlen(entry->d_name);
2588 if (len < 4 || rb->strcmp(entry->d_name + len-4, ".fnt"))
2589 continue;
2591 rb->snprintf(p, len-3, "%s", entry->d_name);
2592 names[i].string = p;
2593 names[i].voice_id = -1;
2594 p += len-3;
2595 i++;
2596 if (i >= count)
2597 break;
2599 rb->closedir(dir);
2601 rb->qsort(names, count, sizeof(struct opt_items), font_comp);
2603 for (i = 0; i < count; i++)
2605 if (!rb->strcmp(names[i].string, prefs.font))
2607 new_font = i;
2608 break;
2611 old_font = new_font;
2613 res = rb->set_option("Select Font", &new_font, INT,
2614 names, count, NULL);
2616 if (new_font != old_font)
2618 rb->memset(prefs.font, 0, MAX_PATH);
2619 rb->snprintf(prefs.font, MAX_PATH, "%s", names[new_font].string);
2620 change_font(prefs.font);
2623 return res;
2626 static bool alignment_setting(void)
2628 static const struct opt_items names[] = {
2629 {"Left", -1},
2630 {"Right", -1},
2633 return rb->set_option("Alignment", &prefs.alignment, INT,
2634 names , 2, NULL);
2636 #endif
2638 static bool autoscroll_speed_setting(void)
2640 return rb->set_int("Auto-scroll Speed", "", UNIT_INT,
2641 &prefs.autoscroll_speed, NULL, 1, 1, 10, NULL);
2644 MENUITEM_FUNCTION(encoding_item, 0, "Encoding", encoding_setting,
2645 NULL, NULL, Icon_NOICON);
2646 MENUITEM_FUNCTION(word_wrap_item, 0, "Word Wrap", word_wrap_setting,
2647 NULL, NULL, Icon_NOICON);
2648 MENUITEM_FUNCTION(line_mode_item, 0, "Line Mode", line_mode_setting,
2649 NULL, NULL, Icon_NOICON);
2650 MENUITEM_FUNCTION(view_mode_item, 0, "Wide View", view_mode_setting,
2651 NULL, NULL, Icon_NOICON);
2652 #ifdef HAVE_LCD_BITMAP
2653 MENUITEM_FUNCTION(alignment_item, 0, "Alignment", alignment_setting,
2654 NULL, NULL, Icon_NOICON);
2655 MENUITEM_FUNCTION(scrollbar_item, 0, "Show Scrollbar", scrollbar_setting,
2656 NULL, NULL, Icon_NOICON);
2657 MENUITEM_FUNCTION(page_mode_item, 0, "Overlap Pages", page_mode_setting,
2658 NULL, NULL, Icon_NOICON);
2659 MENUITEM_FUNCTION(header_item, 0, "Show Header", header_setting,
2660 NULL, NULL, Icon_NOICON);
2661 MENUITEM_FUNCTION(footer_item, 0, "Show Footer", footer_setting,
2662 NULL, NULL, Icon_NOICON);
2663 MENUITEM_FUNCTION(font_item, 0, "Font", font_setting,
2664 NULL, NULL, Icon_NOICON);
2665 #endif
2666 MENUITEM_FUNCTION(scroll_mode_item, 0, "Scroll Mode", scroll_mode_setting,
2667 NULL, NULL, Icon_NOICON);
2668 MENUITEM_FUNCTION(autoscroll_speed_item, 0, "Auto-Scroll Speed",
2669 autoscroll_speed_setting, NULL, NULL, Icon_NOICON);
2670 MAKE_MENU(option_menu, "Viewer Options", NULL, Icon_NOICON,
2671 &encoding_item, &word_wrap_item, &line_mode_item, &view_mode_item,
2672 #ifdef HAVE_LCD_BITMAP
2673 &alignment_item, &scrollbar_item, &page_mode_item, &header_item,
2674 &footer_item, &font_item,
2675 #endif
2676 &scroll_mode_item, &autoscroll_speed_item);
2678 static bool viewer_options_menu(bool is_global)
2680 bool result;
2681 struct preferences tmp_prefs;
2683 rb->memcpy(&tmp_prefs, &prefs, sizeof(struct preferences));
2685 result = (rb->do_menu(&option_menu, NULL, NULL, false) == MENU_ATTACHED_USB);
2687 if (!is_global && rb->memcmp(&tmp_prefs, &prefs, sizeof(struct preferences)))
2689 /* Show-scrollbar mode for current view-width mode */
2690 #ifdef HAVE_LCD_BITMAP
2691 init_need_scrollbar();
2692 init_header_and_footer();
2693 #endif
2694 calc_page();
2696 return result;
2699 static void viewer_menu(void)
2701 int result;
2703 MENUITEM_STRINGLIST(menu, "Viewer Menu", NULL,
2704 "Return", "Viewer Options",
2705 "Show Playback Menu", "Select Bookmark",
2706 "Global Settings", "Quit");
2708 result = rb->do_menu(&menu, NULL, NULL, false);
2709 switch (result)
2711 case 0: /* return */
2712 break;
2713 case 1: /* change settings */
2714 done = viewer_options_menu(false);
2715 break;
2716 case 2: /* playback control */
2717 playback_control(NULL);
2718 break;
2719 case 3: /* select bookmark */
2720 viewer_select_bookmark(viewer_add_last_read_bookmark());
2721 viewer_remove_last_read_bookmark();
2722 fill_buffer(file_pos, buffer, buffer_size);
2723 if (prefs.scroll_mode == PAGE && cline > 1)
2724 viewer_scroll_to_top_line();
2725 break;
2726 case 4: /* change global settings */
2728 struct preferences orig_prefs;
2730 rb->memcpy(&orig_prefs, &prefs, sizeof(struct preferences));
2731 if (!viewer_load_global_settings())
2732 viewer_default_preferences();
2733 done = viewer_options_menu(true);
2734 viewer_save_global_settings();
2735 rb->memcpy(&prefs, &orig_prefs, sizeof(struct preferences));
2737 break;
2738 case 5: /* quit */
2739 viewer_exit(NULL);
2740 done = true;
2741 break;
2743 viewer_draw(col);
2746 enum plugin_status plugin_start(const void* file)
2748 int button, i, ok;
2749 int lastbutton = BUTTON_NONE;
2750 bool autoscroll = false;
2751 long old_tick;
2753 old_tick = *rb->current_tick;
2755 /* get the plugin buffer */
2756 buffer = rb->plugin_get_buffer((size_t *)&buffer_size);
2757 if (buffer_size == 0)
2759 rb->splash(HZ, "buffer does not allocate !!");
2760 return PLUGIN_ERROR;
2762 block_size = buffer_size / 3;
2763 buffer_size = 3 * block_size;
2765 if (!file)
2766 return PLUGIN_ERROR;
2768 file_name = file;
2769 ok = viewer_init();
2770 if (!ok) {
2771 rb->splash(HZ, "Error opening file.");
2772 return PLUGIN_ERROR;
2775 viewer_load_settings(); /* load the preferences and bookmark */
2777 #if LCD_DEPTH > 1
2778 rb->lcd_set_backdrop(NULL);
2779 #endif
2781 viewer_draw(col);
2783 while (!done) {
2785 if(autoscroll)
2787 if(old_tick <= *rb->current_tick - (110-prefs.autoscroll_speed*10))
2789 viewer_scroll_down(true);
2790 viewer_draw(col);
2791 old_tick = *rb->current_tick;
2795 button = rb->button_get_w_tmo(HZ/10);
2797 if (prefs.view_mode != WIDE) {
2798 /* when not in wide view mode, the SCREEN_LEFT and SCREEN_RIGHT
2799 buttons jump to the beginning and end of the file. To stop
2800 users doing this by accident, replace non-held occurrences
2801 with page up/down instead. */
2802 if (button == VIEWER_SCREEN_LEFT)
2803 button = VIEWER_PAGE_UP;
2804 else if (button == VIEWER_SCREEN_RIGHT)
2805 button = VIEWER_PAGE_DOWN;
2808 switch (button) {
2809 case VIEWER_MENU:
2810 #ifdef VIEWER_MENU2
2811 case VIEWER_MENU2:
2812 #endif
2813 viewer_menu();
2814 break;
2816 case VIEWER_AUTOSCROLL:
2817 #ifdef VIEWER_AUTOSCROLL_PRE
2818 if (lastbutton != VIEWER_AUTOSCROLL_PRE)
2819 break;
2820 #endif
2821 autoscroll = !autoscroll;
2822 break;
2824 case VIEWER_PAGE_UP:
2825 case VIEWER_PAGE_UP | BUTTON_REPEAT:
2826 #ifdef VIEWER_PAGE_UP2
2827 case VIEWER_PAGE_UP2:
2828 case VIEWER_PAGE_UP2 | BUTTON_REPEAT:
2829 #endif
2830 if (prefs.scroll_mode == PAGE)
2832 /* Page up */
2833 #ifdef HAVE_LCD_BITMAP
2834 for (i = prefs.page_mode==OVERLAP? 1:0; i < display_lines; i++)
2835 #else
2836 for (i = 0; i < display_lines; i++)
2837 #endif
2838 viewer_scroll_up();
2840 else
2841 viewer_scroll_up();
2842 old_tick = *rb->current_tick;
2843 viewer_draw(col);
2844 break;
2846 case VIEWER_PAGE_DOWN:
2847 case VIEWER_PAGE_DOWN | BUTTON_REPEAT:
2848 #ifdef VIEWER_PAGE_DOWN2
2849 case VIEWER_PAGE_DOWN2:
2850 case VIEWER_PAGE_DOWN2 | BUTTON_REPEAT:
2851 #endif
2852 if (prefs.scroll_mode == PAGE)
2854 /* Page down */
2855 if (next_screen_ptr != NULL)
2857 screen_top_ptr = next_screen_to_draw_ptr;
2858 if (cpage < MAX_PAGE)
2859 cpage++;
2862 else
2863 viewer_scroll_down(autoscroll);
2864 old_tick = *rb->current_tick;
2865 viewer_draw(col);
2866 break;
2868 case VIEWER_SCREEN_LEFT:
2869 case VIEWER_SCREEN_LEFT | BUTTON_REPEAT:
2870 if (prefs.view_mode == WIDE) {
2871 /* Screen left */
2872 col -= draw_columns;
2873 col = col_limit(col);
2875 else { /* prefs.view_mode == NARROW */
2876 /* Top of file */
2877 viewer_top();
2880 viewer_draw(col);
2881 break;
2883 case VIEWER_SCREEN_RIGHT:
2884 case VIEWER_SCREEN_RIGHT | BUTTON_REPEAT:
2885 if (prefs.view_mode == WIDE) {
2886 /* Screen right */
2887 col += draw_columns;
2888 col = col_limit(col);
2890 else { /* prefs.view_mode == NARROW */
2891 /* Bottom of file */
2892 viewer_bottom();
2895 viewer_draw(col);
2896 break;
2898 #ifdef VIEWER_LINE_UP
2899 case VIEWER_LINE_UP:
2900 case VIEWER_LINE_UP | BUTTON_REPEAT:
2901 /* Scroll up one line */
2902 viewer_scroll_up();
2903 old_tick = *rb->current_tick;
2904 viewer_draw(col);
2905 break;
2907 case VIEWER_LINE_DOWN:
2908 case VIEWER_LINE_DOWN | BUTTON_REPEAT:
2909 /* Scroll down one line */
2910 viewer_scroll_down(autoscroll);
2911 increment_current_line();
2912 old_tick = *rb->current_tick;
2913 viewer_draw(col);
2914 break;
2915 #endif
2916 #ifdef VIEWER_COLUMN_LEFT
2917 case VIEWER_COLUMN_LEFT:
2918 case VIEWER_COLUMN_LEFT | BUTTON_REPEAT:
2919 if (prefs.view_mode == WIDE) {
2920 /* Scroll left one column */
2921 col -= glyph_width('o');
2922 col = col_limit(col);
2923 viewer_draw(col);
2925 break;
2927 case VIEWER_COLUMN_RIGHT:
2928 case VIEWER_COLUMN_RIGHT | BUTTON_REPEAT:
2929 if (prefs.view_mode == WIDE) {
2930 /* Scroll right one column */
2931 col += glyph_width('o');
2932 col = col_limit(col);
2933 viewer_draw(col);
2935 break;
2936 #endif
2938 #ifdef VIEWER_RC_QUIT
2939 case VIEWER_RC_QUIT:
2940 #endif
2941 case VIEWER_QUIT:
2942 #ifdef VIEWER_QUIT2
2943 case VIEWER_QUIT2:
2944 #endif
2945 viewer_exit(NULL);
2946 done = true;
2947 break;
2949 case VIEWER_BOOKMARK:
2951 int idx = viewer_find_bookmark(cpage, cline);
2953 if (idx < 0)
2955 if (bookmark_count >= MAX_BOOKMARKS-1)
2956 rb->splash(HZ/2, "No more add bookmark.");
2957 else
2959 viewer_add_bookmark();
2960 rb->splash(HZ/2, "Bookmark add.");
2963 else
2965 viewer_remove_bookmark(idx);
2966 rb->splash(HZ/2, "Bookmark remove.");
2968 viewer_draw(col);
2970 break;
2972 default:
2973 if (rb->default_event_handler_ex(button, viewer_exit, NULL)
2974 == SYS_USB_CONNECTED)
2975 return PLUGIN_USB_CONNECTED;
2976 break;
2978 if (button != BUTTON_NONE)
2980 lastbutton = button;
2981 rb->yield();
2984 return PLUGIN_OK;