fix red
[kugel-rb.git] / apps / plugins / viewer.c
bloba0dd10eed306f2541a8d6cff514daea412f34191
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 * encoding 1
40 * scrollbar_mode 1
41 * need_scrollbar 1
42 * page_mode 1
43 * page_number_mode 1
44 * title_mode 1
45 * scroll_mode 1
46 * autoscroll_speed 1
47 * font name MAX_PATH
49 #define GLOBAL_SETTINGS_FILE VIEWERS_DIR "/viewer.dat"
51 /* temporary file */
52 #define GLOBAL_SETTINGS_TMP_FILE VIEWERS_DIR "/viewer_file.tmp"
54 #define GLOBAL_SETTINGS_HEADER "\x54\x56\x47\x53\x31" /* header="TVGS" version=1 */
55 #define GLOBAL_SETTINGS_H_SIZE 5
57 /* preferences and bookmarks at each file
58 * binary file, so dont use .cfg
60 * setting file format
62 * part byte count
63 * --------------------------------
64 * 'TVS' 3
65 * version 1
66 * file count 2
67 * [1st file]
68 * file path MAX_PATH
69 * next file pos 2
70 * [preferences]
71 * word_mode 1
72 * line_mode 1
73 * view_mode 1
74 * encoding 1
75 * scrollbar_mode 1
76 * need_scrollbar 1
77 * page_mode 1
78 * header_mode 1
79 * footer_mode 1
80 * scroll_mode 1
81 * autoscroll_speed 1
82 * font name MAX_PATH
83 * bookmark count 1
84 * [1st bookmark]
85 * file_position 4
86 * page 2
87 * line 1
88 * flag 1
89 * [2nd bookmark]
90 * ...
91 * [last bookmark]
92 * [2nd file]
93 * ...
94 * [last file]
96 #define SETTINGS_FILE VIEWERS_DIR "/viewer_file.dat"
98 /* temporary file */
99 #define SETTINGS_TMP_FILE VIEWERS_DIR "/viewer_file.tmp"
101 #define SETTINGS_HEADER "\x54\x56\x53\x32" /* header="TVS" version=2 */
102 #define SETTINGS_H_SIZE 4
104 #define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */
105 #define NARROW_MAX_COLUMNS 64 /* Max displayable string len [narrow] (over-estimate) */
106 #define WIDE_MAX_COLUMNS 128 /* Max displayable string len [wide] (over-estimate) */
107 #define MAX_WIDTH 910 /* Max line length in WIDE mode */
108 #define READ_PREV_ZONE (block_size*9/10) /* Arbitrary number less than SMALL_BLOCK_SIZE */
109 #define SMALL_BLOCK_SIZE block_size /* Smallest file chunk we will read */
110 #define LARGE_BLOCK_SIZE (block_size << 1) /* Preferable size of file chunk to read */
111 #define TOP_SECTOR buffer
112 #define MID_SECTOR (buffer + SMALL_BLOCK_SIZE)
113 #define BOTTOM_SECTOR (buffer + (SMALL_BLOCK_SIZE << 1))
114 #undef SCROLLBAR_WIDTH
115 #define SCROLLBAR_WIDTH rb->global_settings->scrollbar_width
116 #define MAX_PAGE 9999
118 #define BOOKMARK_SIZE 8
119 #define MAX_BOOKMARKS 10 /* user setting bookmarks + last read page */
121 #define BOOKMARK_LAST 1
122 #define BOOKMARK_USER 2
124 #ifndef HAVE_LCD_BITMAP
125 #define BOOKMARK_ICON "\xee\x84\x81\x00"
126 #endif
128 #define PREFERENCES_SIZE (11 + MAX_PATH)
130 /* Out-Of-Bounds test for any pointer to data in the buffer */
131 #define BUFFER_OOB(p) ((p) < buffer || (p) >= buffer_end)
133 /* Does the buffer contain the beginning of the file? */
134 #define BUFFER_BOF() (file_pos==0)
136 /* Does the buffer contain the end of the file? */
137 #define BUFFER_EOF() (file_size-file_pos <= buffer_size)
139 /* Formula for the endpoint address outside of buffer data */
140 #define BUFFER_END() \
141 ((BUFFER_EOF()) ? (file_size-file_pos+buffer) : (buffer+buffer_size))
143 /* Is the entire file being shown in one screen? */
144 #define ONE_SCREEN_FITS_ALL() \
145 (next_screen_ptr==NULL && screen_top_ptr==buffer && BUFFER_BOF())
147 /* Is a scrollbar called for on the current screen? */
148 #define NEED_SCROLLBAR() \
149 ((!(ONE_SCREEN_FITS_ALL())) && (prefs.scrollbar_mode==SB_ON))
151 /* variable button definitions */
153 /* Recorder keys */
154 #if CONFIG_KEYPAD == RECORDER_PAD
155 #define VIEWER_QUIT BUTTON_OFF
156 #define VIEWER_PAGE_UP BUTTON_UP
157 #define VIEWER_PAGE_DOWN BUTTON_DOWN
158 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
159 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
160 #define VIEWER_MENU BUTTON_F1
161 #define VIEWER_AUTOSCROLL BUTTON_PLAY
162 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
163 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
164 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
165 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
166 #define VIEWER_BOOKMARK BUTTON_F2
168 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
169 #define VIEWER_QUIT BUTTON_OFF
170 #define VIEWER_PAGE_UP BUTTON_UP
171 #define VIEWER_PAGE_DOWN BUTTON_DOWN
172 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
173 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
174 #define VIEWER_MENU BUTTON_F1
175 #define VIEWER_AUTOSCROLL BUTTON_SELECT
176 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
177 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
178 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
179 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
180 #define VIEWER_BOOKMARK BUTTON_F2
182 /* Ondio keys */
183 #elif CONFIG_KEYPAD == ONDIO_PAD
184 #define VIEWER_QUIT BUTTON_OFF
185 #define VIEWER_PAGE_UP BUTTON_UP
186 #define VIEWER_PAGE_DOWN BUTTON_DOWN
187 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
188 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
189 #define VIEWER_MENU (BUTTON_MENU|BUTTON_REPEAT)
190 #define VIEWER_AUTOSCROLL_PRE BUTTON_MENU
191 #define VIEWER_AUTOSCROLL (BUTTON_MENU|BUTTON_REL)
192 #define VIEWER_BOOKMARK (BUTTON_MENU|BUTTON_OFF)
194 /* Player keys */
195 #elif CONFIG_KEYPAD == PLAYER_PAD
196 #define VIEWER_QUIT BUTTON_STOP
197 #define VIEWER_PAGE_UP BUTTON_LEFT
198 #define VIEWER_PAGE_DOWN BUTTON_RIGHT
199 #define VIEWER_SCREEN_LEFT (BUTTON_ON|BUTTON_LEFT)
200 #define VIEWER_SCREEN_RIGHT (BUTTON_ON|BUTTON_RIGHT)
201 #define VIEWER_MENU BUTTON_MENU
202 #define VIEWER_AUTOSCROLL BUTTON_PLAY
203 #define VIEWER_BOOKMARK BUTTON_ON
205 /* iRiver H1x0 && H3x0 keys */
206 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
207 (CONFIG_KEYPAD == IRIVER_H300_PAD)
208 #define VIEWER_QUIT BUTTON_OFF
209 #define VIEWER_PAGE_UP BUTTON_UP
210 #define VIEWER_PAGE_DOWN BUTTON_DOWN
211 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
212 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
213 #define VIEWER_MENU BUTTON_MODE
214 #define VIEWER_AUTOSCROLL BUTTON_SELECT
215 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
216 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
217 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
218 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
219 #define VIEWER_BOOKMARK (BUTTON_ON | BUTTON_SELECT)
221 #define VIEWER_RC_QUIT BUTTON_RC_STOP
223 /* iPods */
224 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
225 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
226 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
227 #define VIEWER_QUIT_PRE BUTTON_SELECT
228 #define VIEWER_QUIT (BUTTON_SELECT | BUTTON_MENU)
229 #define VIEWER_PAGE_UP BUTTON_SCROLL_BACK
230 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_FWD
231 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
232 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
233 #define VIEWER_MENU BUTTON_MENU
234 #define VIEWER_AUTOSCROLL BUTTON_PLAY
235 #define VIEWER_BOOKMARK BUTTON_SELECT
237 /* iFP7xx keys */
238 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
239 #define VIEWER_QUIT BUTTON_PLAY
240 #define VIEWER_PAGE_UP BUTTON_UP
241 #define VIEWER_PAGE_DOWN BUTTON_DOWN
242 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
243 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
244 #define VIEWER_MENU BUTTON_MODE
245 #define VIEWER_AUTOSCROLL BUTTON_SELECT
246 #define VIEWER_BOOKMARK (BUTTON_LEFT|BUTTON_SELECT)
248 /* iAudio X5 keys */
249 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
250 #define VIEWER_QUIT BUTTON_POWER
251 #define VIEWER_PAGE_UP BUTTON_UP
252 #define VIEWER_PAGE_DOWN BUTTON_DOWN
253 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
254 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
255 #define VIEWER_MENU BUTTON_SELECT
256 #define VIEWER_AUTOSCROLL BUTTON_PLAY
257 #define VIEWER_BOOKMARK BUTTON_REC
259 /* GIGABEAT keys */
260 #elif CONFIG_KEYPAD == GIGABEAT_PAD
261 #define VIEWER_QUIT BUTTON_POWER
262 #define VIEWER_PAGE_UP BUTTON_UP
263 #define VIEWER_PAGE_DOWN BUTTON_DOWN
264 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
265 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
266 #define VIEWER_MENU BUTTON_MENU
267 #define VIEWER_AUTOSCROLL BUTTON_A
268 #define VIEWER_BOOKMARK BUTTON_SELECT
270 /* Sansa E200 keys */
271 #elif CONFIG_KEYPAD == SANSA_E200_PAD
272 #define VIEWER_QUIT BUTTON_POWER
273 #define VIEWER_PAGE_UP BUTTON_UP
274 #define VIEWER_PAGE_DOWN BUTTON_DOWN
275 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
276 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
277 #define VIEWER_MENU BUTTON_SELECT
278 #define VIEWER_AUTOSCROLL BUTTON_REC
279 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
280 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
281 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
283 /* Sansa Fuze keys */
284 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
285 #define VIEWER_QUIT (BUTTON_HOME|BUTTON_REPEAT)
286 #define VIEWER_PAGE_UP BUTTON_UP
287 #define VIEWER_PAGE_DOWN BUTTON_DOWN
288 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
289 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
290 #define VIEWER_MENU BUTTON_SELECT|BUTTON_REPEAT
291 #define VIEWER_AUTOSCROLL BUTTON_SELECT|BUTTON_DOWN
292 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
293 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
294 #define VIEWER_BOOKMARK BUTTON_SELECT
296 /* Sansa C200 keys */
297 #elif CONFIG_KEYPAD == SANSA_C200_PAD
298 #define VIEWER_QUIT BUTTON_POWER
299 #define VIEWER_PAGE_UP BUTTON_VOL_UP
300 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
301 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
302 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
303 #define VIEWER_MENU BUTTON_SELECT
304 #define VIEWER_AUTOSCROLL BUTTON_REC
305 #define VIEWER_LINE_UP BUTTON_UP
306 #define VIEWER_LINE_DOWN BUTTON_DOWN
307 #define VIEWER_BOOKMARK (BUTTON_DOWN | BUTTON_SELECT)
309 /* Sansa Clip keys */
310 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
311 #define VIEWER_QUIT BUTTON_POWER
312 #define VIEWER_PAGE_UP BUTTON_VOL_UP
313 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
314 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
315 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
316 #define VIEWER_MENU BUTTON_SELECT
317 #define VIEWER_AUTOSCROLL BUTTON_HOME
318 #define VIEWER_LINE_UP BUTTON_UP
319 #define VIEWER_LINE_DOWN BUTTON_DOWN
320 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
322 /* Sansa M200 keys */
323 #elif CONFIG_KEYPAD == SANSA_M200_PAD
324 #define VIEWER_QUIT BUTTON_POWER
325 #define VIEWER_PAGE_UP BUTTON_VOL_UP
326 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
327 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
328 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
329 #define VIEWER_MENU (BUTTON_SELECT | BUTTON_UP)
330 #define VIEWER_AUTOSCROLL (BUTTON_SELECT | BUTTON_REL)
331 #define VIEWER_LINE_UP BUTTON_UP
332 #define VIEWER_LINE_DOWN BUTTON_DOWN
333 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
335 /* iriver H10 keys */
336 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
337 #define VIEWER_QUIT BUTTON_POWER
338 #define VIEWER_PAGE_UP BUTTON_SCROLL_UP
339 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_DOWN
340 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
341 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
342 #define VIEWER_MENU BUTTON_REW
343 #define VIEWER_AUTOSCROLL BUTTON_PLAY
344 #define VIEWER_BOOKMARK BUTTON_FF
346 /*M-Robe 500 keys */
347 #elif CONFIG_KEYPAD == MROBE500_PAD
348 #define VIEWER_QUIT BUTTON_POWER
349 #define VIEWER_PAGE_UP BUTTON_RC_PLAY
350 #define VIEWER_PAGE_DOWN BUTTON_RC_DOWN
351 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
352 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
353 #define VIEWER_MENU BUTTON_RC_HEART
354 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
355 #define VIEWER_BOOKMARK BUTTON_CENTER
357 /*Gigabeat S keys */
358 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
359 #define VIEWER_QUIT BUTTON_BACK
360 #define VIEWER_PAGE_UP BUTTON_PREV
361 #define VIEWER_PAGE_DOWN BUTTON_NEXT
362 #define VIEWER_SCREEN_LEFT (BUTTON_PLAY | BUTTON_LEFT)
363 #define VIEWER_SCREEN_RIGHT (BUTTON_PLAY | BUTTON_RIGHT)
364 #define VIEWER_MENU BUTTON_MENU
365 #define VIEWER_AUTOSCROLL_PRE BUTTON_PLAY
366 #define VIEWER_AUTOSCROLL (BUTTON_PLAY|BUTTON_REL)
367 #define VIEWER_LINE_UP BUTTON_UP
368 #define VIEWER_LINE_DOWN BUTTON_DOWN
369 #define VIEWER_COLUMN_LEFT BUTTON_LEFT
370 #define VIEWER_COLUMN_RIGHT BUTTON_RIGHT
371 #define VIEWER_BOOKMARK BUTTON_SELECT
373 /*M-Robe 100 keys */
374 #elif CONFIG_KEYPAD == MROBE100_PAD
375 #define VIEWER_QUIT BUTTON_POWER
376 #define VIEWER_PAGE_UP BUTTON_UP
377 #define VIEWER_PAGE_DOWN BUTTON_DOWN
378 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
379 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
380 #define VIEWER_MENU BUTTON_MENU
381 #define VIEWER_AUTOSCROLL BUTTON_DISPLAY
382 #define VIEWER_BOOKMARK BUTTON_SELECT
384 /* iAUdio M3 keys */
385 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
386 #define VIEWER_QUIT BUTTON_REC
387 #define VIEWER_PAGE_UP BUTTON_RC_VOL_UP
388 #define VIEWER_PAGE_DOWN BUTTON_RC_VOL_DOWN
389 #define VIEWER_SCREEN_LEFT BUTTON_RC_REW
390 #define VIEWER_SCREEN_RIGHT BUTTON_RC_FF
391 #define VIEWER_MENU BUTTON_RC_MENU
392 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
393 #define VIEWER_RC_QUIT BUTTON_RC_REC
394 #define VIEWER_BOOKMARK BUTTON_RC_PLAY
396 /* Cowon D2 keys */
397 #elif CONFIG_KEYPAD == COWON_D2_PAD
398 #define VIEWER_QUIT BUTTON_POWER
399 #define VIEWER_MENU BUTTON_MENU
400 #define VIEWER_PAGE_UP BUTTON_MINUS
401 #define VIEWER_PAGE_DOWN BUTTON_PLUS
402 #define VIEWER_BOOKMARK (BUTTON_MENU|BUTTON_PLUS)
404 #elif CONFIG_KEYPAD == IAUDIO67_PAD
405 #define VIEWER_QUIT BUTTON_POWER
406 #define VIEWER_PAGE_UP BUTTON_VOLUP
407 #define VIEWER_PAGE_DOWN BUTTON_VOLDOWN
408 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
409 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
410 #define VIEWER_MENU BUTTON_MENU
411 #define VIEWER_AUTOSCROLL BUTTON_PLAY
412 #define VIEWER_RC_QUIT BUTTON_STOP
413 #define VIEWER_BOOKMARK (BUTTON_LEFT|BUTTON_PLAY)
415 /* Creative Zen Vision:M keys */
416 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
417 #define VIEWER_QUIT BUTTON_BACK
418 #define VIEWER_PAGE_UP BUTTON_UP
419 #define VIEWER_PAGE_DOWN BUTTON_DOWN
420 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
421 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
422 #define VIEWER_MENU BUTTON_MENU
423 #define VIEWER_AUTOSCROLL BUTTON_SELECT
424 #define VIEWER_BOOKMARK BUTTON_PLAY
426 /* Philips HDD1630 keys */
427 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
428 #define VIEWER_QUIT BUTTON_POWER
429 #define VIEWER_PAGE_UP BUTTON_UP
430 #define VIEWER_PAGE_DOWN BUTTON_DOWN
431 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
432 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
433 #define VIEWER_MENU BUTTON_MENU
434 #define VIEWER_AUTOSCROLL BUTTON_VIEW
435 #define VIEWER_BOOKMARK BUTTON_SELECT
437 /* Philips SA9200 keys */
438 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
439 #define VIEWER_QUIT BUTTON_POWER
440 #define VIEWER_PAGE_UP BUTTON_UP
441 #define VIEWER_PAGE_DOWN BUTTON_DOWN
442 #define VIEWER_SCREEN_LEFT BUTTON_PREV
443 #define VIEWER_SCREEN_RIGHT BUTTON_NEXT
444 #define VIEWER_MENU BUTTON_MENU
445 #define VIEWER_AUTOSCROLL BUTTON_PLAY
446 #define VIEWER_BOOKMARK BUTTON_RIGHT
448 /* Onda VX747 keys */
449 #elif CONFIG_KEYPAD == ONDAVX747_PAD
450 #define VIEWER_QUIT BUTTON_POWER
451 #define VIEWER_MENU BUTTON_MENU
452 #define VIEWER_BOOKMARK BUTTON_RIGHT
454 /* Onda VX777 keys */
455 #elif CONFIG_KEYPAD == ONDAVX777_PAD
456 #define VIEWER_QUIT BUTTON_POWER
457 #define VIEWER_BOOKMARK BUTTON_RIGHT
459 /* SAMSUNG YH-820 / YH-920 / YH-925 keys */
460 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
461 #define VIEWER_QUIT BUTTON_REC
462 #define VIEWER_PAGE_UP BUTTON_UP
463 #define VIEWER_PAGE_DOWN BUTTON_DOWN
464 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
465 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
466 #define VIEWER_MENU BUTTON_PLAY
467 #define VIEWER_AUTOSCROLL BUTTON_REW
468 #define VIEWER_BOOKMARK BUTTON_FFWD
470 /* Packard Bell Vibe 500 keys */
471 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
472 #define VIEWER_QUIT BUTTON_REC
473 #define VIEWER_PAGE_UP BUTTON_OK
474 #define VIEWER_PAGE_DOWN BUTTON_CANCEL
475 #define VIEWER_LINE_UP BUTTON_UP
476 #define VIEWER_LINE_DOWN BUTTON_DOWN
477 #define VIEWER_SCREEN_LEFT BUTTON_PREV
478 #define VIEWER_SCREEN_RIGHT BUTTON_NEXT
479 #define VIEWER_MENU BUTTON_MENU
480 #define VIEWER_AUTOSCROLL BUTTON_PLAY
481 #define VIEWER_BOOKMARK BUTTON_POWER
483 #else
484 #error No keymap defined!
485 #endif
487 #ifdef HAVE_TOUCHSCREEN
488 #ifdef VIEWER_QUIT
489 #define VIEWER_QUIT2 BUTTON_TOPLEFT
490 #else
491 #define VIEWER_QUIT BUTTON_TOPLEFT
492 #endif
493 #ifdef VIEWER_PAGE_UP
494 #define VIEWER_PAGE_UP2 BUTTON_TOPMIDDLE
495 #else
496 #define VIEWER_PAGE_UP BUTTON_TOPMIDDLE
497 #endif
498 #ifdef VIEWER_PAGE_DOWN
499 #define VIEWER_PAGE_DOWN2 BUTTON_BOTTOMMIDDLE
500 #else
501 #define VIEWER_PAGE_DOWN BUTTON_BOTTOMMIDDLE
502 #endif
503 #ifndef VIEWER_SCREEN_LEFT
504 #define VIEWER_SCREEN_LEFT BUTTON_MIDLEFT
505 #endif
506 #ifndef VIEWER_SCREEN_RIGHT
507 #define VIEWER_SCREEN_RIGHT BUTTON_MIDRIGHT
508 #endif
509 #ifdef VIEWER_MENU
510 #define VIEWER_MENU2 BUTTON_TOPRIGHT
511 #else
512 #define VIEWER_MENU BUTTON_TOPRIGHT
513 #endif
514 #ifndef VIEWER_AUTOSCROLL
515 #define VIEWER_AUTOSCROLL BUTTON_CENTER
516 #endif
517 #endif
519 /* stuff for the bookmarking */
520 struct bookmark_info {
521 long file_position;
522 int page;
523 int line;
524 unsigned char flag;
527 struct preferences {
528 enum {
529 WRAP=0,
530 CHOP,
531 } word_mode;
533 enum {
534 NORMAL=0,
535 JOIN,
536 EXPAND,
537 REFLOW, /* won't be set on charcell LCD, must be last */
538 } line_mode;
540 enum {
541 NARROW=0,
542 WIDE,
543 } view_mode;
545 enum codepages encoding;
547 enum {
548 SB_OFF=0,
549 SB_ON,
550 } scrollbar_mode;
551 bool need_scrollbar;
553 enum {
554 NO_OVERLAP=0,
555 OVERLAP,
556 } page_mode;
558 enum {
559 HD_NONE = 0,
560 HD_PATH,
561 HD_SBAR,
562 HD_BOTH,
563 } header_mode;
565 enum {
566 FT_NONE = 0,
567 FT_PAGE,
568 FT_SBAR,
569 FT_BOTH,
570 } footer_mode;
572 enum {
573 PAGE=0,
574 LINE,
575 } scroll_mode;
577 int autoscroll_speed;
579 unsigned char font[MAX_PATH];
582 enum {
583 VIEWER_FONT_MENU = 0,
584 VIEWER_FONT_TEXT,
587 struct preferences prefs;
588 struct preferences old_prefs;
590 static unsigned char *buffer;
591 static long buffer_size;
592 static long block_size = 0x1000;
593 static unsigned char line_break[] = {0,0x20,9,0xB,0xC,'-'};
594 static int display_columns; /* number of (pixel) columns on the display */
595 static int display_lines; /* number of lines on the display */
596 static int draw_columns; /* number of (pixel) columns available for text */
597 static int par_indent_spaces; /* number of spaces to indent first paragraph */
598 static int fd;
599 static const char *file_name;
600 static long file_size;
601 static long start_position; /* position in the file after the viewer is started */
602 static bool mac_text;
603 static long file_pos; /* Position of the top of the buffer in the file */
604 static long last_file_pos;
605 static unsigned char *buffer_end; /*Set to BUFFER_END() when file_pos changes*/
606 static int max_line_len;
607 static int max_width;
608 static int max_columns;
609 static int cline = 1;
610 static int cpage = 1;
611 static int lpage = 0;
612 static unsigned char *screen_top_ptr;
613 static unsigned char *next_screen_ptr;
614 static unsigned char *next_screen_to_draw_ptr;
615 static unsigned char *next_line_ptr;
616 static unsigned char *last_screen_top_ptr = NULL;
617 #ifdef HAVE_LCD_BITMAP
618 static struct font *pf;
619 static int header_height = 0;
620 static int footer_height = 0;
621 #endif
622 struct bookmark_info bookmarks[MAX_BOOKMARKS];
623 static int bookmark_count;
625 /* UTF-8 BOM */
626 #define BOM "\xef\xbb\xbf"
627 #define BOM_SIZE 3
629 static bool is_bom = false;
631 static int glyph_width(int ch)
633 if (ch == 0)
634 ch = ' ';
636 #ifdef HAVE_LCD_BITMAP
637 return rb->font_get_width(pf, ch);
638 #else
639 return 1;
640 #endif
643 static unsigned char* get_ucs(const unsigned char* str, unsigned short* ch)
645 unsigned char utf8_tmp[6];
646 int count;
648 if (prefs.encoding == UTF_8)
649 return (unsigned char*)rb->utf8decode(str, ch);
651 count = BUFFER_OOB(str+2)? 1:2;
652 rb->iso_decode(str, utf8_tmp, prefs.encoding, count);
653 rb->utf8decode(utf8_tmp, ch);
655 #ifdef HAVE_LCD_BITMAP
656 if (prefs.encoding >= SJIS && *str >= 0x80
657 && !(prefs.encoding == SJIS && *str > 0xA0 && *str < 0xE0))
658 return (unsigned char*)str+2;
659 else
660 #endif
661 return (unsigned char*)str+1;
664 static unsigned char *decode2utf8(const unsigned char *src, unsigned char *dst,
665 int skip_width, int disp_width)
667 unsigned short ch;
668 const unsigned char *oldstr;
669 const unsigned char *str = src;
670 unsigned char *utf8 = dst;
671 int width = 0;
673 while (*str != '\0')
675 oldstr = str;
676 str = get_ucs(oldstr, &ch);
677 width += glyph_width(ch);
678 if (width > skip_width)
680 str = oldstr;
681 break;
684 width = 0;
685 while(*str != '\0')
687 str = get_ucs(str, &ch);
688 width += glyph_width(ch);
689 if (width > disp_width)
690 break;
692 utf8 = rb->utf8encode(ch, utf8);
695 return utf8;
698 static void calc_max_width(void)
700 if (prefs.view_mode == NARROW)
702 max_columns = NARROW_MAX_COLUMNS;
703 max_width = draw_columns;
705 else
707 max_columns = WIDE_MAX_COLUMNS;
708 max_width = 2 * draw_columns;
712 bool done = false;
713 int col = 0;
715 #define ADVANCE_COUNTERS(c) { width += glyph_width(c); k++; }
716 #define LINE_IS_FULL ((k>=max_columns-1) ||( width >= max_width))
717 #define LINE_IS_NOT_FULL ((k<max_columns-1) &&( width < max_width))
718 static unsigned char* crop_at_width(const unsigned char* p)
720 int k,width;
721 unsigned short ch;
722 const unsigned char *oldp = p;
724 k=width=0;
726 while (LINE_IS_NOT_FULL) {
727 oldp = p;
728 if (BUFFER_OOB(p))
729 break;
730 p = get_ucs(p, &ch);
731 ADVANCE_COUNTERS(ch);
734 return (unsigned char*)oldp;
737 static unsigned char* find_first_feed(const unsigned char* p, int size)
739 int i;
741 for (i=0; i < size; i++)
742 if (p[i] == 0)
743 return (unsigned char*) p+i;
745 return NULL;
748 static unsigned char* find_last_feed(const unsigned char* p, int size)
750 int i;
752 for (i=size-1; i>=0; i--)
753 if (p[i] == 0)
754 return (unsigned char*) p+i;
756 return NULL;
759 static unsigned char* find_last_space(const unsigned char* p, int size)
761 int i, j, k;
763 k = (prefs.line_mode==JOIN) || (prefs.line_mode==REFLOW) ? 0:1;
765 if (!BUFFER_OOB(&p[size]))
766 for (j=k; j < ((int) sizeof(line_break)) - 1; j++)
767 if (p[size] == line_break[j])
768 return (unsigned char*) p+size;
770 for (i=size-1; i>=0; i--)
771 for (j=k; j < (int) sizeof(line_break); j++)
773 if (!((p[i] == '-') && (prefs.word_mode == WRAP)))
774 if (p[i] == line_break[j])
775 return (unsigned char*) p+i;
778 return NULL;
781 static unsigned char* find_next_line(const unsigned char* cur_line, bool *is_short)
783 const unsigned char *next_line = NULL;
784 int size, i, j, k, width, search_len, spaces, newlines;
785 bool first_chars;
786 unsigned char c;
788 if (is_short != NULL)
789 *is_short = true;
791 if BUFFER_OOB(cur_line)
792 return NULL;
794 if (prefs.view_mode == WIDE) {
795 search_len = MAX_WIDTH;
797 else { /* prefs.view_mode == NARROW */
798 search_len = crop_at_width(cur_line) - cur_line;
801 size = BUFFER_OOB(cur_line+search_len) ? buffer_end-cur_line : search_len;
803 if ((prefs.line_mode == JOIN) || (prefs.line_mode == REFLOW)) {
804 /* Need to scan ahead and possibly increase search_len and size,
805 or possibly set next_line at second hard return in a row. */
806 next_line = NULL;
807 first_chars=true;
808 for (j=k=width=spaces=newlines=0; ; j++) {
809 if (BUFFER_OOB(cur_line+j))
810 return NULL;
811 if (LINE_IS_FULL) {
812 size = search_len = j;
813 break;
816 c = cur_line[j];
817 switch (c) {
818 case ' ':
819 if (prefs.line_mode == REFLOW) {
820 if (newlines > 0) {
821 size = j;
822 next_line = cur_line + size;
823 return (unsigned char*) next_line;
825 if (j==0) /* i=1 is intentional */
826 for (i=0; i<par_indent_spaces; i++)
827 ADVANCE_COUNTERS(' ');
829 if (!first_chars) spaces++;
830 break;
832 case 0:
833 if (newlines > 0) {
834 size = j;
835 next_line = cur_line + size - spaces;
836 if (next_line != cur_line)
837 return (unsigned char*) next_line;
838 break;
841 newlines++;
842 size += spaces -1;
843 if (BUFFER_OOB(cur_line+size) || size > 2*search_len)
844 return NULL;
845 search_len = size;
846 spaces = first_chars? 0:1;
847 break;
849 default:
850 if (prefs.line_mode==JOIN || newlines>0) {
851 while (spaces) {
852 spaces--;
853 ADVANCE_COUNTERS(' ');
854 if (LINE_IS_FULL) {
855 size = search_len = j;
856 break;
859 newlines=0;
860 } else if (spaces) {
861 /* REFLOW, multiple spaces between words: count only
862 * one. If more are needed, they will be added
863 * while drawing. */
864 search_len = size;
865 spaces=0;
866 ADVANCE_COUNTERS(' ');
867 if (LINE_IS_FULL) {
868 size = search_len = j;
869 break;
872 first_chars = false;
873 ADVANCE_COUNTERS(c);
874 break;
878 else {
879 /* find first hard return */
880 next_line = find_first_feed(cur_line, size);
883 if (next_line == NULL)
884 if (size == search_len) {
885 if (prefs.word_mode == WRAP) /* Find last space */
886 next_line = find_last_space(cur_line, size);
888 if (next_line == NULL)
889 next_line = crop_at_width(cur_line);
890 else
891 if (prefs.word_mode == WRAP)
892 for (i=0;
893 i<WRAP_TRIM && isspace(next_line[0]) && !BUFFER_OOB(next_line);
894 i++)
895 next_line++;
898 if (prefs.line_mode == EXPAND)
899 if (!BUFFER_OOB(next_line)) /* Not Null & not out of bounds */
900 if (next_line[0] == 0)
901 if (next_line != cur_line)
902 return (unsigned char*) next_line;
904 /* If next_line is pointing to a zero, increment it; i.e.,
905 leave the terminator at the end of cur_line. If pointing
906 to a hyphen, increment only if there is room to display
907 the hyphen on current line (won't apply in WIDE mode,
908 since it's guarenteed there won't be room). */
909 if (!BUFFER_OOB(next_line)) /* Not Null & not out of bounds */
910 if (next_line[0] == 0)/* ||
911 (next_line[0] == '-' && next_line-cur_line < draw_columns)) */
912 next_line++;
914 if (BUFFER_OOB(next_line))
916 if (BUFFER_EOF() && next_line != cur_line)
917 return (unsigned char*) next_line;
918 return NULL;
921 if (is_short)
922 *is_short = false;
924 return (unsigned char*) next_line;
927 static unsigned char* find_prev_line(const unsigned char* cur_line)
929 const unsigned char *prev_line = NULL;
930 const unsigned char *p;
932 if BUFFER_OOB(cur_line)
933 return NULL;
935 /* To wrap consistently at the same places, we must
936 start with a known hard return, then work downwards.
937 We can either search backwards for a hard return,
938 or simply start wrapping downwards from top of buffer.
939 If current line is not near top of buffer, this is
940 a file with long lines (paragraphs). We would need to
941 read earlier sectors before we could decide how to
942 properly wrap the lines above the current line, but
943 it probably is not worth the disk access. Instead,
944 start with top of buffer and wrap down from there.
945 This may result in some lines wrapping at different
946 points from where they wrap when scrolling down.
947 If buffer is at top of file, start at top of buffer. */
949 if ((prefs.line_mode == JOIN) || (prefs.line_mode == REFLOW))
950 prev_line = p = NULL;
951 else
952 prev_line = p = find_last_feed(buffer, cur_line-buffer-1);
953 /* Null means no line feeds in buffer above current line. */
955 if (prev_line == NULL)
956 if (BUFFER_BOF() || cur_line - buffer > READ_PREV_ZONE)
957 prev_line = p = buffer;
958 /* (else return NULL and read previous block) */
960 /* Wrap downwards until too far, then use the one before. */
961 while (p != NULL && p < cur_line) {
962 prev_line = p;
963 p = find_next_line(prev_line, NULL);
966 if (BUFFER_OOB(prev_line))
967 return NULL;
969 return (unsigned char*) prev_line;
972 static void check_bom(void)
974 unsigned char bom[BOM_SIZE];
975 off_t orig = rb->lseek(fd, 0, SEEK_CUR);
977 is_bom = false;
979 rb->lseek(fd, 0, SEEK_SET);
981 if (rb->read(fd, bom, BOM_SIZE) == BOM_SIZE)
982 is_bom = !memcmp(bom, BOM, BOM_SIZE);
984 rb->lseek(fd, orig, SEEK_SET);
987 static void fill_buffer(long pos, unsigned char* buf, unsigned size)
989 /* Read from file and preprocess the data */
990 /* To minimize disk access, always read on sector boundaries */
991 unsigned numread, i;
992 bool found_CR = false;
993 off_t offset = rb->lseek(fd, pos, SEEK_SET);
995 if (offset == 0 && prefs.encoding == UTF_8 && is_bom)
996 rb->lseek(fd, BOM_SIZE, SEEK_SET);
998 numread = rb->read(fd, buf, size);
999 buf[numread] = 0;
1000 rb->button_clear_queue(); /* clear button queue */
1002 for(i = 0; i < numread; i++) {
1003 switch(buf[i]) {
1004 case '\r':
1005 if (mac_text) {
1006 buf[i] = 0;
1008 else {
1009 buf[i] = ' ';
1010 found_CR = true;
1012 break;
1014 case '\n':
1015 buf[i] = 0;
1016 found_CR = false;
1017 break;
1019 case 0: /* No break between case 0 and default, intentionally */
1020 buf[i] = ' ';
1021 default:
1022 if (found_CR) {
1023 buf[i - 1] = 0;
1024 found_CR = false;
1025 mac_text = true;
1027 break;
1032 static int viewer_find_bookmark(int page, int line)
1034 int i;
1036 for (i = 0; i < bookmark_count; i++)
1038 if (bookmarks[i].page == page && bookmarks[i].line == line)
1039 return i;
1041 return -1;
1044 static int read_and_synch(int direction)
1046 /* Read next (or prev) block, and reposition global pointers. */
1047 /* direction: 1 for down (i.e., further into file), -1 for up */
1048 int move_size, move_vector, offset;
1049 unsigned char *fill_buf;
1051 if (direction == -1) /* up */ {
1052 move_size = SMALL_BLOCK_SIZE;
1053 offset = 0;
1054 fill_buf = TOP_SECTOR;
1055 rb->memcpy(BOTTOM_SECTOR, MID_SECTOR, SMALL_BLOCK_SIZE);
1056 rb->memcpy(MID_SECTOR, TOP_SECTOR, SMALL_BLOCK_SIZE);
1058 else /* down */ {
1059 if (prefs.view_mode == WIDE) {
1060 /* WIDE mode needs more buffer so we have to read smaller blocks */
1061 move_size = SMALL_BLOCK_SIZE;
1062 offset = LARGE_BLOCK_SIZE;
1063 fill_buf = BOTTOM_SECTOR;
1064 rb->memcpy(TOP_SECTOR, MID_SECTOR, SMALL_BLOCK_SIZE);
1065 rb->memcpy(MID_SECTOR, BOTTOM_SECTOR, SMALL_BLOCK_SIZE);
1067 else {
1068 move_size = LARGE_BLOCK_SIZE;
1069 offset = SMALL_BLOCK_SIZE;
1070 fill_buf = MID_SECTOR;
1071 rb->memcpy(TOP_SECTOR, BOTTOM_SECTOR, SMALL_BLOCK_SIZE);
1074 move_vector = direction * move_size;
1075 screen_top_ptr -= move_vector;
1076 file_pos += move_vector;
1077 buffer_end = BUFFER_END(); /* Update whenever file_pos changes */
1078 fill_buffer(file_pos + offset, fill_buf, move_size);
1079 return move_vector;
1082 static void get_next_line_position(unsigned char **line_begin,
1083 unsigned char **line_end,
1084 bool *is_short)
1086 int resynch_move;
1088 *line_begin = *line_end;
1089 *line_end = find_next_line(*line_begin, is_short);
1091 if (*line_end == NULL && !BUFFER_EOF())
1093 resynch_move = read_and_synch(1); /* Read block & move ptrs */
1094 *line_begin -= resynch_move;
1095 if (next_line_ptr > buffer)
1096 next_line_ptr -= resynch_move;
1098 *line_end = find_next_line(*line_begin, is_short);
1102 static void increment_current_line(void)
1104 if (cline < display_lines)
1105 cline++;
1106 else if (cpage < MAX_PAGE)
1108 cpage++;
1109 cline = 1;
1113 static void decrement_current_line(void)
1115 if (cline > 1)
1116 cline--;
1117 else if (cpage > 1)
1119 cpage--;
1120 cline = display_lines;
1124 static void viewer_scroll_up(void)
1126 unsigned char *p;
1128 p = find_prev_line(screen_top_ptr);
1129 if (p == NULL && !BUFFER_BOF()) {
1130 read_and_synch(-1);
1131 p = find_prev_line(screen_top_ptr);
1133 if (p != NULL)
1134 screen_top_ptr = p;
1136 decrement_current_line();
1139 static void viewer_scroll_down(bool autoscroll)
1141 if (cpage == lpage)
1142 return;
1144 if (next_line_ptr != NULL)
1145 screen_top_ptr = next_line_ptr;
1147 if (prefs.scroll_mode == LINE || autoscroll)
1148 increment_current_line();
1151 static void viewer_scroll_to_top_line(void)
1153 int line;
1155 for (line = cline; line > 1; line--)
1156 viewer_scroll_up();
1159 #ifdef HAVE_LCD_BITMAP
1160 static void viewer_scrollbar(void) {
1161 int items, min_shown, max_shown, sb_begin_y, sb_height;
1163 items = (int) file_size; /* (SH1 int is same as long) */
1164 min_shown = (int) file_pos + (screen_top_ptr - buffer);
1166 if (next_screen_ptr == NULL)
1167 max_shown = items;
1168 else
1169 max_shown = min_shown + (next_screen_ptr - screen_top_ptr);
1171 sb_begin_y = header_height;
1172 sb_height = LCD_HEIGHT - header_height - footer_height;
1174 rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN],0, sb_begin_y,
1175 SCROLLBAR_WIDTH-1, sb_height,
1176 items, min_shown, max_shown, VERTICAL);
1178 #endif
1180 #ifdef HAVE_LCD_BITMAP
1181 static void viewer_show_header(void)
1183 if (prefs.header_mode == HD_SBAR || prefs.header_mode == HD_BOTH)
1184 rb->gui_syncstatusbar_draw(rb->statusbars, true);
1186 if (prefs.header_mode == HD_PATH || prefs.header_mode == HD_BOTH)
1187 rb->lcd_putsxy(0, header_height - pf->height, file_name);
1190 static void viewer_show_footer(void)
1192 if (prefs.footer_mode == FT_SBAR || prefs.footer_mode == FT_BOTH)
1193 rb->gui_syncstatusbar_draw(rb->statusbars, true);
1195 if (prefs.footer_mode == FT_PAGE || prefs.footer_mode == FT_BOTH)
1197 unsigned char buf[12];
1199 if (cline == 1)
1200 rb->snprintf(buf, sizeof(buf), "%d", cpage);
1201 else
1202 rb->snprintf(buf, sizeof(buf), "%d - %d", cpage, cpage+1);
1204 rb->lcd_putsxy(0, LCD_HEIGHT - footer_height, buf);
1207 #endif
1209 static void viewer_draw(int col)
1211 int i, j, k, line_len, line_width, spaces, left_col=0;
1212 int width, extra_spaces, indent_spaces, spaces_per_word;
1213 bool multiple_spacing, line_is_short;
1214 unsigned short ch;
1215 unsigned char *str, *oldstr;
1216 unsigned char *line_begin;
1217 unsigned char *line_end;
1218 unsigned char c;
1219 unsigned char scratch_buffer[max_columns + 1];
1220 unsigned char utf8_buffer[max_columns*4 + 1];
1221 unsigned char *endptr;
1223 /* If col==-1 do all calculations but don't display */
1224 if (col != -1) {
1225 #ifdef HAVE_LCD_BITMAP
1226 left_col = prefs.need_scrollbar? SCROLLBAR_WIDTH:0;
1227 #else
1228 left_col = 0;
1229 #endif
1230 rb->lcd_clear_display();
1232 max_line_len = 0;
1233 line_begin = line_end = screen_top_ptr;
1235 for (i = 0; i < display_lines; i++) {
1236 if (BUFFER_OOB(line_end))
1238 if (lpage == cpage)
1239 break; /* Happens after display last line at BUFFER_EOF() */
1241 if (lpage == 0 && cline == 1)
1243 lpage = cpage;
1244 last_screen_top_ptr = screen_top_ptr;
1245 last_file_pos = file_pos;
1249 get_next_line_position(&line_begin, &line_end, &line_is_short);
1250 if (line_end == NULL)
1252 if (BUFFER_OOB(line_begin))
1253 break;
1254 line_end = buffer_end + 1;
1257 line_len = line_end - line_begin;
1259 /* calculate line_len */
1260 str = oldstr = line_begin;
1261 j = -1;
1262 while (str < line_end) {
1263 oldstr = str;
1264 str = crop_at_width(str);
1265 j++;
1267 line_width = j*draw_columns;
1268 while (oldstr < line_end) {
1269 oldstr = get_ucs(oldstr, &ch);
1270 line_width += glyph_width(ch);
1273 if (prefs.line_mode == JOIN) {
1274 if (line_begin[0] == 0) {
1275 line_begin++;
1276 if (prefs.word_mode == CHOP)
1277 line_end++;
1278 else
1279 line_len--;
1281 for (j=k=spaces=0; j < line_len; j++) {
1282 if (k == max_columns)
1283 break;
1285 c = line_begin[j];
1286 switch (c) {
1287 case ' ':
1288 spaces++;
1289 break;
1290 case 0:
1291 spaces = 0;
1292 scratch_buffer[k++] = ' ';
1293 break;
1294 default:
1295 while (spaces) {
1296 spaces--;
1297 scratch_buffer[k++] = ' ';
1298 if (k == max_columns - 1)
1299 break;
1301 scratch_buffer[k++] = c;
1302 break;
1305 if (col != -1) {
1306 scratch_buffer[k] = 0;
1307 endptr = decode2utf8(scratch_buffer, utf8_buffer, col, draw_columns);
1308 *endptr = 0;
1311 else if (prefs.line_mode == REFLOW) {
1312 if (line_begin[0] == 0) {
1313 line_begin++;
1314 if (prefs.word_mode == CHOP)
1315 line_end++;
1316 else
1317 line_len--;
1320 indent_spaces = 0;
1321 if (!line_is_short) {
1322 multiple_spacing = false;
1323 width=spaces=0;
1324 for (str = line_begin; str < line_end; ) {
1325 str = get_ucs(str, &ch);
1326 switch (ch) {
1327 case ' ':
1328 case 0:
1329 if ((str == line_begin) && (prefs.word_mode==WRAP))
1330 /* special case: indent the paragraph,
1331 * don't count spaces */
1332 indent_spaces = par_indent_spaces;
1333 else if (!multiple_spacing)
1334 spaces++;
1335 multiple_spacing = true;
1336 break;
1337 default:
1338 multiple_spacing = false;
1339 width += glyph_width(ch);
1340 break;
1343 if (multiple_spacing) spaces--;
1345 if (spaces) {
1346 /* total number of spaces to insert between words */
1347 extra_spaces = (max_width-width)/glyph_width(' ')
1348 - indent_spaces;
1349 /* number of spaces between each word*/
1350 spaces_per_word = extra_spaces / spaces;
1351 /* number of words with n+1 spaces (to fill up) */
1352 extra_spaces = extra_spaces % spaces;
1353 if (spaces_per_word > 2) { /* too much spacing is awful */
1354 spaces_per_word = 3;
1355 extra_spaces = 0;
1357 } else { /* this doesn't matter much... no spaces anyway */
1358 spaces_per_word = extra_spaces = 0;
1360 } else { /* end of a paragraph: don't fill line */
1361 spaces_per_word = 1;
1362 extra_spaces = 0;
1365 multiple_spacing = false;
1366 for (j=k=spaces=0; j < line_len; j++) {
1367 if (k == max_columns)
1368 break;
1370 c = line_begin[j];
1371 switch (c) {
1372 case ' ':
1373 case 0:
1374 if (j==0 && prefs.word_mode==WRAP) { /* indent paragraph */
1375 for (j=0; j<par_indent_spaces; j++)
1376 scratch_buffer[k++] = ' ';
1377 j=0;
1379 else if (!multiple_spacing) {
1380 for (width = spaces<extra_spaces ? -1:0; width < spaces_per_word; width++)
1381 scratch_buffer[k++] = ' ';
1382 spaces++;
1384 multiple_spacing = true;
1385 break;
1386 default:
1387 scratch_buffer[k++] = c;
1388 multiple_spacing = false;
1389 break;
1392 if (col != -1) {
1393 scratch_buffer[k] = 0;
1394 endptr = decode2utf8(scratch_buffer, utf8_buffer, col, draw_columns);
1395 *endptr = 0;
1398 else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */
1399 if (col != -1)
1400 if (line_width > col) {
1401 str = oldstr = line_begin;
1402 k = col;
1403 width = 0;
1404 while( (width<draw_columns) && (oldstr<line_end) )
1406 oldstr = get_ucs(oldstr, &ch);
1407 if (k > 0) {
1408 k -= glyph_width(ch);
1409 line_begin = oldstr;
1410 } else {
1411 width += glyph_width(ch);
1415 if(prefs.view_mode==WIDE)
1416 endptr = rb->iso_decode(line_begin, utf8_buffer,
1417 prefs.encoding, oldstr-line_begin);
1418 else
1419 endptr = rb->iso_decode(line_begin, utf8_buffer,
1420 prefs.encoding, line_end-line_begin);
1421 *endptr = 0;
1424 if (col != -1 && line_width > col)
1426 int dpage = (cline+i <= display_lines)?cpage:cpage+1;
1427 int dline = cline+i - ((cline+i <= display_lines)?0:display_lines);
1428 bool bflag = (viewer_find_bookmark(dpage, dline) >= 0);
1429 #ifdef HAVE_LCD_BITMAP
1430 int dy = i * pf->height + header_height;
1431 #endif
1432 if (bflag)
1433 #ifdef HAVE_LCD_BITMAP
1435 rb->lcd_set_drawmode(DRMODE_BG|DRMODE_FG);
1436 rb->lcd_fillrect(left_col, dy, LCD_WIDTH, pf->height);
1437 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1439 rb->lcd_putsxy(left_col, dy, utf8_buffer);
1440 rb->lcd_set_drawmode(DRMODE_SOLID);
1441 #else
1443 rb->lcd_puts(left_col, i, BOOKMARK_ICON);
1445 rb->lcd_puts(left_col+1, i, utf8_buffer);
1446 #endif
1448 if (line_width > max_line_len)
1449 max_line_len = line_width;
1451 if (i == 0)
1452 next_line_ptr = line_end;
1454 next_screen_ptr = line_end;
1455 if (BUFFER_OOB(next_screen_ptr))
1456 next_screen_ptr = NULL;
1458 #ifdef HAVE_LCD_BITMAP
1459 next_screen_to_draw_ptr = prefs.page_mode==OVERLAP? line_begin: next_screen_ptr;
1461 if (prefs.need_scrollbar)
1462 viewer_scrollbar();
1463 #else
1464 next_screen_to_draw_ptr = next_screen_ptr;
1465 #endif
1467 #ifdef HAVE_LCD_BITMAP
1468 /* show header */
1469 viewer_show_header();
1471 /* show footer */
1472 viewer_show_footer();
1473 #endif
1475 if (col != -1)
1476 rb->lcd_update();
1479 static void viewer_top(void)
1481 /* Read top of file into buffer
1482 and point screen pointer to top */
1483 if (file_pos != 0)
1485 rb->splash(0, "Loading...");
1487 file_pos = 0;
1488 buffer_end = BUFFER_END(); /* Update whenever file_pos changes */
1489 fill_buffer(0, buffer, buffer_size);
1492 screen_top_ptr = buffer;
1493 cpage = 1;
1494 cline = 1;
1497 static void viewer_bottom(void)
1499 unsigned char *line_begin;
1500 unsigned char *line_end;
1502 rb->splash(0, "Loading...");
1504 if (last_screen_top_ptr)
1506 cpage = lpage;
1507 cline = 1;
1508 screen_top_ptr = last_screen_top_ptr;
1509 file_pos = last_file_pos;
1510 fill_buffer(file_pos, buffer, buffer_size);
1511 buffer_end = BUFFER_END();
1512 return;
1515 line_end = screen_top_ptr;
1517 while (!BUFFER_EOF() || !BUFFER_OOB(line_end))
1519 get_next_line_position(&line_begin, &line_end, NULL);
1520 if (line_end == NULL)
1521 break;
1523 increment_current_line();
1524 if (cline == 1)
1525 screen_top_ptr = line_end;
1527 lpage = cpage;
1528 cline = 1;
1529 last_screen_top_ptr = screen_top_ptr;
1530 last_file_pos = file_pos;
1531 buffer_end = BUFFER_END();
1534 #ifdef HAVE_LCD_BITMAP
1535 static void init_need_scrollbar(void) {
1536 /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
1537 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
1538 viewer_draw(-1);
1539 prefs.need_scrollbar = NEED_SCROLLBAR();
1540 draw_columns = prefs.need_scrollbar? display_columns-SCROLLBAR_WIDTH : display_columns;
1541 par_indent_spaces = draw_columns/(5*glyph_width(' '));
1542 calc_max_width();
1545 static void init_header_and_footer(void)
1547 header_height = 0;
1548 footer_height = 0;
1549 if (rb->global_settings->statusbar == STATUSBAR_TOP)
1551 if (prefs.header_mode == HD_SBAR || prefs.header_mode == HD_BOTH)
1552 header_height = STATUSBAR_HEIGHT;
1554 if (prefs.footer_mode == FT_SBAR)
1555 prefs.footer_mode = FT_NONE;
1556 else if (prefs.footer_mode == FT_BOTH)
1557 prefs.footer_mode = FT_PAGE;
1559 else if (rb->global_settings->statusbar == STATUSBAR_BOTTOM)
1561 if (prefs.footer_mode == FT_SBAR || prefs.footer_mode == FT_BOTH)
1562 footer_height = STATUSBAR_HEIGHT;
1564 if (prefs.header_mode == HD_SBAR)
1565 prefs.header_mode = HD_NONE;
1566 else if (prefs.header_mode == HD_BOTH)
1567 prefs.header_mode = HD_PATH;
1569 else /* STATUSBAR_OFF || STATUSBAR_CUSTOM */
1571 if (prefs.header_mode == HD_SBAR)
1572 prefs.header_mode = HD_NONE;
1573 else if (prefs.header_mode == HD_BOTH)
1574 prefs.header_mode = HD_PATH;
1576 if (prefs.footer_mode == FT_SBAR)
1577 prefs.footer_mode = FT_NONE;
1578 else if (prefs.footer_mode == FT_BOTH)
1579 prefs.footer_mode = FT_PAGE;
1582 if (prefs.header_mode == HD_NONE || prefs.header_mode == HD_PATH ||
1583 prefs.footer_mode == FT_NONE || prefs.footer_mode == FT_PAGE)
1584 rb->gui_syncstatusbar_draw(rb->statusbars, false);
1586 if (prefs.header_mode == HD_PATH || prefs.header_mode == HD_BOTH)
1587 header_height += pf->height;
1588 if (prefs.footer_mode == FT_PAGE || prefs.footer_mode == FT_BOTH)
1589 footer_height += pf->height;
1591 display_lines = (LCD_HEIGHT - header_height - footer_height) / pf->height;
1593 lpage = 0;
1594 last_file_pos = 0;
1595 last_screen_top_ptr = NULL;
1598 static void change_font(unsigned char *font)
1600 unsigned char buf[MAX_PATH];
1602 if (font == NULL || *font == '\0')
1603 return;
1605 rb->snprintf(buf, MAX_PATH, "%s/%s.fnt", FONT_DIR, font);
1606 if (rb->font_load(NULL, buf) < 0)
1607 rb->splash(HZ/2, "font load failed.");
1609 #endif
1611 static bool viewer_init(void)
1613 #ifdef HAVE_LCD_BITMAP
1614 /* initialize fonts */
1615 pf = rb->font_get(FONT_UI);
1616 draw_columns = display_columns = LCD_WIDTH;
1617 #else
1618 /* REAL fixed pitch :) all chars use up 1 cell */
1619 display_lines = 2;
1620 draw_columns = display_columns = 11;
1621 par_indent_spaces = 2;
1622 #endif
1624 fd = rb->open(file_name, O_RDONLY);
1625 if (fd < 0)
1626 return false;
1628 /* Init mac_text value used in processing buffer */
1629 mac_text = false;
1631 return true;
1634 /* When a file is UTF-8 file with BOM, if prefs.encoding is UTF-8,
1635 * then file size decreases only BOM_SIZE.
1637 static void get_filesize(void)
1639 file_size = rb->filesize(fd);
1640 if (file_size == -1)
1641 return;
1643 if (prefs.encoding == UTF_8 && is_bom)
1644 file_size -= BOM_SIZE;
1647 static int bm_comp(const void *a, const void *b)
1649 struct bookmark_info *pa;
1650 struct bookmark_info *pb;
1652 pa = (struct bookmark_info*)a;
1653 pb = (struct bookmark_info*)b;
1655 if (pa->page != pb->page)
1656 return pa->page - pb->page;
1658 return pa->line - pb->line;
1661 static void viewer_add_bookmark(void)
1663 if (bookmark_count >= MAX_BOOKMARKS-1)
1664 return;
1666 bookmarks[bookmark_count].file_position
1667 = file_pos + screen_top_ptr - buffer;
1668 bookmarks[bookmark_count].page = cpage;
1669 bookmarks[bookmark_count].line = cline;
1670 bookmarks[bookmark_count].flag = BOOKMARK_USER;
1671 bookmark_count++;
1674 static int viewer_add_last_read_bookmark(void)
1676 int i;
1678 i = viewer_find_bookmark(cpage, cline);
1679 if (i >= 0)
1680 bookmarks[i].flag |= BOOKMARK_LAST;
1681 else
1683 viewer_add_bookmark();
1684 i = bookmark_count-1;
1685 bookmarks[i].flag = BOOKMARK_LAST;
1687 return i;
1690 static void viewer_remove_bookmark(int i)
1692 int j;
1694 if (i < 0 || i >= bookmark_count)
1695 return;
1697 for (j = i+1; j < bookmark_count; j++)
1698 rb->memcpy(&bookmarks[j-1], &bookmarks[j],
1699 sizeof(struct bookmark_info));
1701 bookmark_count--;
1704 static void viewer_remove_last_read_bookmark(void)
1706 int i, j;
1708 for (i = 0; i < bookmark_count; i++)
1710 if (bookmarks[i].flag & BOOKMARK_LAST)
1712 if (bookmarks[i].flag == BOOKMARK_LAST)
1714 for (j = i+1; j < bookmark_count; j++)
1715 rb->memcpy(&bookmarks[j-1], &bookmarks[j],
1716 sizeof(struct bookmark_info));
1718 bookmark_count--;
1720 else
1721 bookmarks[i].flag = BOOKMARK_USER;
1722 break;
1727 static int viewer_get_last_read_bookmark(void)
1729 int i;
1731 for (i = 0; i < bookmark_count; i++)
1733 if (bookmarks[i].flag & BOOKMARK_LAST)
1734 return i;
1736 return -1;
1739 static void viewer_select_bookmark(int initval)
1741 int i;
1742 int ipage = 0;
1743 int iline = 0;
1744 int screen_pos;
1745 int screen_top;
1746 int selected = -1;
1748 struct opt_items items[bookmark_count];
1749 unsigned char names[bookmark_count][38];
1751 if (initval >= 0 && initval < bookmark_count)
1753 ipage = bookmarks[initval].page;
1754 iline = bookmarks[initval].line;
1757 rb->qsort(bookmarks, bookmark_count, sizeof(struct bookmark_info),
1758 bm_comp);
1760 for (i = 0; i < bookmark_count; i++)
1762 rb->snprintf(names[i], sizeof(names[0]),
1763 #if CONFIG_KEYPAD != PLAYER_PAD
1764 "%sPage: %d Line: %d",
1765 #else
1766 "%sP:%d L:%d",
1767 #endif
1768 (bookmarks[i].flag&BOOKMARK_LAST)? "*":" ",
1769 bookmarks[i].page,
1770 bookmarks[i].line);
1771 items[i].string = names[i];
1772 items[i].voice_id = -1;
1773 if (selected < 0 && bookmarks[i].page == ipage && bookmarks[i].line == iline)
1774 selected = i;
1777 rb->set_option("Select bookmark", &selected, INT, items,
1778 sizeof(items) / sizeof(items[0]), NULL);
1780 if (selected < 0 || selected >= bookmark_count)
1782 if (initval < 0 || (selected = viewer_get_last_read_bookmark()) < 0)
1784 if (initval < 0)
1785 rb->splash(HZ, "Start the first page.");
1786 file_pos = 0;
1787 screen_top_ptr = buffer;
1788 cpage = 1;
1789 cline = 1;
1790 buffer_end = BUFFER_END();
1791 return;
1795 screen_pos = bookmarks[selected].file_position;
1796 screen_top = screen_pos % buffer_size;
1797 file_pos = screen_pos - screen_top;
1798 screen_top_ptr = buffer + screen_top;
1799 cpage = bookmarks[selected].page;
1800 cline = bookmarks[selected].line;
1801 buffer_end = BUFFER_END();
1804 static void viewer_default_preferences(void)
1806 prefs.word_mode = WRAP;
1807 prefs.line_mode = NORMAL;
1808 prefs.view_mode = NARROW;
1809 prefs.scroll_mode = PAGE;
1810 prefs.page_mode = NO_OVERLAP;
1811 prefs.scrollbar_mode = SB_OFF;
1812 rb->memset(prefs.font, 0, MAX_PATH);
1813 #ifdef HAVE_LCD_BITMAP
1814 prefs.header_mode = HD_BOTH;
1815 prefs.footer_mode = FT_BOTH;
1816 rb->snprintf(prefs.font, MAX_PATH, "%s", rb->global_settings->font_file);
1817 #else
1818 prefs.header_mode = HD_NONE;
1819 prefs.footer_mode = FT_NONE;
1820 #endif
1821 prefs.autoscroll_speed = 1;
1822 /* Set codepage to system default */
1823 prefs.encoding = rb->global_settings->default_codepage;
1826 static bool viewer_read_preferences(int pfd)
1828 unsigned char buf[PREFERENCES_SIZE];
1829 unsigned char *p = buf;
1831 if (rb->read(pfd, buf, sizeof(buf)) != sizeof(buf))
1832 return false;
1834 prefs.word_mode = *p++;
1835 prefs.line_mode = *p++;
1836 prefs.view_mode = *p++;
1837 prefs.encoding = *p++;
1838 prefs.scrollbar_mode = *p++;
1839 prefs.need_scrollbar = *p++;
1840 prefs.page_mode = *p++;
1841 prefs.header_mode = *p++;
1842 prefs.footer_mode = *p++;
1843 prefs.scroll_mode = *p++;
1844 prefs.autoscroll_speed = *p++;
1845 rb->memcpy(prefs.font, p, MAX_PATH);
1847 return true;
1850 static bool viewer_write_preferences(int pfd)
1852 unsigned char buf[PREFERENCES_SIZE];
1853 unsigned char *p = buf;
1855 *p++ = prefs.word_mode;
1856 *p++ = prefs.line_mode;
1857 *p++ = prefs.view_mode;
1858 *p++ = prefs.encoding;
1859 *p++ = prefs.scrollbar_mode;
1860 *p++ = prefs.need_scrollbar;
1861 *p++ = prefs.page_mode;
1862 *p++ = prefs.header_mode;
1863 *p++ = prefs.footer_mode;
1864 *p++ = prefs.scroll_mode;
1865 *p++ = prefs.autoscroll_speed;
1866 rb->memcpy(p, prefs.font, MAX_PATH);
1868 return (rb->write(pfd, buf, sizeof(buf)) == sizeof(buf));
1871 static bool viewer_read_bookmark_info(int bfd, struct bookmark_info *b)
1873 unsigned char buf[BOOKMARK_SIZE];
1875 if (rb->read(bfd, buf, sizeof(buf)) != sizeof(buf))
1876 return false;
1878 b->file_position = (buf[0] << 24)|(buf[1] << 16)|(buf[2] << 8)|buf[3];
1879 b->page = (buf[4] << 8)|buf[5];
1880 b->line = buf[6];
1881 b->flag = buf[7];
1883 return true;
1886 static bool viewer_read_bookmark_infos(int bfd)
1888 unsigned char c;
1889 int i;
1891 if (rb->read(bfd, &c, 1) != 1)
1893 bookmark_count = 0;
1894 return false;
1897 bookmark_count = c;
1898 if (bookmark_count > MAX_BOOKMARKS)
1899 bookmark_count = MAX_BOOKMARKS;
1901 for (i = 0; i < bookmark_count; i++)
1903 if (!viewer_read_bookmark_info(bfd, &bookmarks[i]))
1905 bookmark_count = i;
1906 return false;
1909 return true;
1912 static bool viewer_write_bookmark_info(int bfd, struct bookmark_info *b)
1914 unsigned char buf[BOOKMARK_SIZE];
1915 unsigned char *p = buf;
1916 unsigned long ul;
1918 ul = b->file_position;
1919 *p++ = ul >> 24;
1920 *p++ = ul >> 16;
1921 *p++ = ul >> 8;
1922 *p++ = ul;
1924 ul = b->page;
1925 *p++ = ul >> 8;
1926 *p++ = ul;
1928 *p++ = b->line;
1929 *p = b->flag;
1931 return (rb->write(bfd, buf, sizeof(buf)) == sizeof(buf));
1934 static bool viewer_write_bookmark_infos(int bfd)
1936 unsigned char c = bookmark_count;
1937 int i;
1939 if (rb->write(bfd, &c, 1) != 1)
1940 return false;
1942 for (i = 0; i < bookmark_count; i++)
1944 if (!viewer_write_bookmark_info(bfd, &bookmarks[i]))
1945 return false;
1948 return true;
1951 static bool viewer_load_global_settings(void)
1953 unsigned buf[GLOBAL_SETTINGS_H_SIZE];
1954 int sfd = rb->open(GLOBAL_SETTINGS_FILE, O_RDONLY);
1956 if (sfd < 0)
1957 return false;
1959 if ((rb->read(sfd, buf, GLOBAL_SETTINGS_H_SIZE) != GLOBAL_SETTINGS_H_SIZE) ||
1960 rb->memcmp(buf, GLOBAL_SETTINGS_HEADER, GLOBAL_SETTINGS_H_SIZE) ||
1961 !viewer_read_preferences(sfd))
1963 rb->close(sfd);
1964 return false;
1966 rb->close(sfd);
1967 return true;
1970 static bool viewer_save_global_settings(void)
1972 int sfd = rb->open(GLOBAL_SETTINGS_TMP_FILE, O_WRONLY|O_CREAT|O_TRUNC);
1974 if (sfd < 0)
1975 return false;
1977 if (rb->write(sfd, &GLOBAL_SETTINGS_HEADER, GLOBAL_SETTINGS_H_SIZE)
1978 != GLOBAL_SETTINGS_H_SIZE ||
1979 !viewer_write_preferences(sfd))
1981 rb->close(sfd);
1982 rb->remove(GLOBAL_SETTINGS_TMP_FILE);
1983 return false;
1985 rb->close(sfd);
1986 rb->remove(GLOBAL_SETTINGS_FILE);
1987 rb->rename(GLOBAL_SETTINGS_TMP_FILE, GLOBAL_SETTINGS_FILE);
1988 return true;
1991 static void viewer_load_settings(void)
1993 unsigned char buf[MAX_PATH+2];
1994 unsigned int fcount;
1995 unsigned int i;
1996 bool res = false;
1997 int sfd;
1998 unsigned int size;
2000 sfd = rb->open(SETTINGS_FILE, O_RDONLY);
2001 if (sfd < 0)
2002 goto read_end;
2004 if ((rb->read(sfd, buf, SETTINGS_H_SIZE+2) != SETTINGS_H_SIZE+2) ||
2005 rb->memcmp(buf, SETTINGS_HEADER, SETTINGS_H_SIZE))
2007 /* illegal setting file */
2008 rb->close(sfd);
2010 if (rb->file_exists(SETTINGS_FILE))
2011 rb->remove(SETTINGS_FILE);
2013 goto read_end;
2016 fcount = (buf[SETTINGS_H_SIZE] << 8) | buf[SETTINGS_H_SIZE+1];
2017 for (i = 0; i < fcount; i++)
2019 if (rb->read(sfd, buf, MAX_PATH+2) != MAX_PATH+2)
2020 break;
2022 size = (buf[MAX_PATH] << 8) | buf[MAX_PATH+1];
2023 if (rb->strcmp(buf, file_name))
2025 if (rb->lseek(sfd, size, SEEK_CUR) < 0)
2026 break;
2027 continue;
2029 if (!viewer_read_preferences(sfd))
2030 break;
2032 res = viewer_read_bookmark_infos(sfd);
2033 break;
2036 rb->close(sfd);
2038 read_end:
2039 if (!res)
2041 /* load global settings */
2042 if (!viewer_load_global_settings())
2043 viewer_default_preferences();
2045 file_pos = 0;
2046 screen_top_ptr = buffer;
2047 cpage = 1;
2048 cline = 1;
2049 bookmark_count = 0;
2052 rb->memcpy(&old_prefs, &prefs, sizeof(struct preferences));
2053 calc_max_width();
2055 if (bookmark_count > 1)
2056 viewer_select_bookmark(-1);
2057 else if (bookmark_count == 1)
2059 int screen_pos;
2060 int screen_top;
2062 screen_pos = bookmarks[0].file_position;
2063 screen_top = screen_pos % buffer_size;
2064 file_pos = screen_pos - screen_top;
2065 screen_top_ptr = buffer + screen_top;
2066 cpage = bookmarks[0].page;
2067 cline = bookmarks[0].line;
2070 viewer_remove_last_read_bookmark();
2072 check_bom();
2073 get_filesize();
2075 buffer_end = BUFFER_END(); /* Update whenever file_pos changes */
2077 if (BUFFER_OOB(screen_top_ptr))
2078 screen_top_ptr = buffer;
2080 fill_buffer(file_pos, buffer, buffer_size);
2081 if (prefs.scroll_mode == PAGE && cline > 1)
2082 viewer_scroll_to_top_line();
2084 /* remember the current position */
2085 start_position = file_pos + screen_top_ptr - buffer;
2087 #ifdef HAVE_LCD_BITMAP
2088 if (rb->strcmp(prefs.font, rb->global_settings->font_file))
2089 change_font(prefs.font);
2091 init_need_scrollbar();
2092 init_header_and_footer();
2093 #endif
2096 static bool copy_bookmark_file(int sfd, int dfd, off_t start, off_t size)
2098 off_t rsize;
2100 if (rb->lseek(sfd, start, SEEK_SET) < 0)
2101 return false;
2103 while (size > 0)
2105 if (size > buffer_size)
2106 rsize = buffer_size;
2107 else
2108 rsize = size;
2109 size -= rsize;
2111 if (rb->read(sfd, buffer, rsize) != rsize ||
2112 rb->write(dfd, buffer, rsize) != rsize)
2113 return false;
2115 return true;
2118 static bool viewer_save_settings(void)
2120 unsigned char buf[MAX_PATH+2];
2121 unsigned int fcount = 0;
2122 unsigned int i;
2123 int idx;
2124 int ofd;
2125 int tfd;
2126 off_t first_copy_size = 0;
2127 off_t second_copy_start_pos = 0;
2128 off_t size;
2130 /* add reading page to bookmarks */
2131 idx = viewer_find_bookmark(cpage, cline);
2132 if (idx >= 0)
2133 bookmarks[idx].flag |= BOOKMARK_LAST;
2134 else
2136 viewer_add_bookmark();
2137 bookmarks[bookmark_count-1].flag = BOOKMARK_LAST;
2140 tfd = rb->open(SETTINGS_TMP_FILE, O_WRONLY|O_CREAT|O_TRUNC);
2141 if (tfd < 0)
2142 return false;
2144 ofd = rb->open(SETTINGS_FILE, O_RDWR);
2145 if (ofd >= 0)
2147 if ((rb->read(ofd, buf, SETTINGS_H_SIZE+2) != SETTINGS_H_SIZE+2) ||
2148 rb->memcmp(buf, SETTINGS_HEADER, SETTINGS_H_SIZE))
2150 rb->close(ofd);
2151 goto save_err;
2153 fcount = (buf[SETTINGS_H_SIZE] << 8) | buf[SETTINGS_H_SIZE+1];
2155 for (i = 0; i < fcount; i++)
2157 if (rb->read(ofd, buf, MAX_PATH+2) != MAX_PATH+2)
2159 rb->close(ofd);
2160 goto save_err;
2162 size = (buf[MAX_PATH] << 8) | buf[MAX_PATH+1];
2163 if (rb->strcmp(buf, file_name))
2165 if (rb->lseek(ofd, size, SEEK_CUR) < 0)
2167 rb->close(ofd);
2168 goto save_err;
2171 else
2173 first_copy_size = rb->lseek(ofd, 0, SEEK_CUR);
2174 if (first_copy_size < 0)
2176 rb->close(ofd);
2177 goto save_err;
2179 second_copy_start_pos = first_copy_size + size;
2180 first_copy_size -= MAX_PATH+2;
2181 fcount--;
2182 break;
2185 if (first_copy_size == 0)
2186 first_copy_size = rb->filesize(ofd);
2188 if (!copy_bookmark_file(ofd, tfd, 0, first_copy_size))
2190 rb->close(ofd);
2191 goto save_err;
2193 if (second_copy_start_pos > 0)
2195 if (!copy_bookmark_file(ofd, tfd, second_copy_start_pos,
2196 rb->filesize(ofd) - second_copy_start_pos))
2198 rb->close(ofd);
2199 goto save_err;
2202 rb->close(ofd);
2204 else
2206 rb->memcpy(buf, SETTINGS_HEADER, SETTINGS_H_SIZE);
2207 buf[SETTINGS_H_SIZE] = 0;
2208 buf[SETTINGS_H_SIZE+1] = 0;
2209 if (rb->write(tfd, buf, SETTINGS_H_SIZE+2) != SETTINGS_H_SIZE+2)
2210 goto save_err;
2213 /* copy to current read file's bookmarks */
2214 rb->memset(buf, 0, MAX_PATH);
2215 rb->snprintf(buf, MAX_PATH, "%s", file_name);
2217 size = PREFERENCES_SIZE + bookmark_count * BOOKMARK_SIZE + 1;
2218 buf[MAX_PATH] = size >> 8;
2219 buf[MAX_PATH+1] = size;
2221 if (rb->write(tfd, buf, MAX_PATH+2) != MAX_PATH+2)
2222 goto save_err;
2224 if (!viewer_write_preferences(tfd))
2225 goto save_err;
2227 if (!viewer_write_bookmark_infos(tfd))
2228 goto save_err;
2230 if (rb->lseek(tfd, SETTINGS_H_SIZE, SEEK_SET) < 0)
2231 goto save_err;
2233 fcount++;
2234 buf[0] = fcount >> 8;
2235 buf[1] = fcount;
2237 if (rb->write(tfd, buf, 2) != 2)
2238 goto save_err;
2240 rb->close(tfd);
2242 rb->remove(SETTINGS_FILE);
2243 rb->rename(SETTINGS_TMP_FILE, SETTINGS_FILE);
2245 return true;
2247 save_err:
2248 rb->close(tfd);
2249 rb->remove(SETTINGS_TMP_FILE);
2250 return false;
2253 static void viewer_exit(void *parameter)
2255 (void)parameter;
2257 /* save preference and bookmarks */
2258 if (!viewer_save_settings())
2259 rb->splash(HZ, "Can't save preference and bookmarks.");
2261 rb->close(fd);
2262 #ifdef HAVE_LCD_BITMAP
2263 if (rb->strcmp(prefs.font, rb->global_settings->font_file))
2264 change_font(rb->global_settings->font_file);
2265 #endif
2268 static void calc_page(void)
2270 int i;
2271 unsigned char *line_begin;
2272 unsigned char *line_end;
2273 off_t sfp;
2274 unsigned char *sstp;
2276 rb->splash(0, "Calculating page/line number...");
2278 /* add reading page to bookmarks */
2279 viewer_add_last_read_bookmark();
2281 rb->qsort(bookmarks, bookmark_count, sizeof(struct bookmark_info),
2282 bm_comp);
2284 cpage = 1;
2285 cline = 1;
2286 file_pos = 0;
2287 screen_top_ptr = buffer;
2288 buffer_end = BUFFER_END();
2290 fill_buffer(file_pos, buffer, buffer_size);
2291 line_end = line_begin = buffer;
2293 for (i = 0; i < bookmark_count; i++)
2295 sfp = bookmarks[i].file_position;
2296 sstp = buffer;
2298 while ((line_begin > sstp || sstp >= line_end) ||
2299 (file_pos > sfp || sfp >= file_pos + BUFFER_END() - buffer))
2301 get_next_line_position(&line_begin, &line_end, NULL);
2302 if (line_end == NULL)
2303 break;
2305 next_line_ptr = line_end;
2307 if (sstp == buffer &&
2308 file_pos <= sfp && sfp < file_pos + BUFFER_END() - buffer)
2309 sstp = sfp - file_pos + buffer;
2311 increment_current_line();
2314 decrement_current_line();
2315 bookmarks[i].page = cpage;
2316 bookmarks[i].line = cline;
2317 bookmarks[i].file_position = file_pos + (line_begin - buffer);
2318 increment_current_line();
2321 /* remove reading page's bookmark */
2322 for (i = 0; i < bookmark_count; i++)
2324 if (bookmarks[i].flag & BOOKMARK_LAST)
2326 int screen_pos;
2327 int screen_top;
2329 screen_pos = bookmarks[i].file_position;
2330 screen_top = screen_pos % buffer_size;
2331 file_pos = screen_pos - screen_top;
2332 screen_top_ptr = buffer + screen_top;
2334 cpage = bookmarks[i].page;
2335 cline = bookmarks[i].line;
2336 bookmarks[i].flag ^= BOOKMARK_LAST;
2337 buffer_end = BUFFER_END();
2339 fill_buffer(file_pos, buffer, buffer_size);
2341 if (bookmarks[i].flag == 0)
2342 viewer_remove_bookmark(i);
2344 if (prefs.scroll_mode == PAGE && cline > 1)
2345 viewer_scroll_to_top_line();
2346 break;
2351 static int col_limit(int col)
2353 if (col < 0)
2354 col = 0;
2355 else
2356 if (col >= max_width)
2357 col = max_width - draw_columns;
2359 return col;
2362 /* settings helper functions */
2364 static bool encoding_setting(void)
2366 static struct opt_items names[NUM_CODEPAGES];
2367 int idx;
2368 bool res;
2369 enum codepages oldenc = prefs.encoding;
2371 for (idx = 0; idx < NUM_CODEPAGES; idx++)
2373 names[idx].string = rb->get_codepage_name(idx);
2374 names[idx].voice_id = -1;
2377 res = rb->set_option("Encoding", &prefs.encoding, INT, names,
2378 sizeof(names) / sizeof(names[0]), NULL);
2380 /* When prefs.encoding changes into UTF-8 or changes from UTF-8,
2381 * filesize (file_size) might change.
2382 * In addition, if prefs.encoding is UTF-8, then BOM does not read.
2384 if (oldenc != prefs.encoding && (oldenc == UTF_8 || prefs.encoding == UTF_8))
2386 check_bom();
2387 get_filesize();
2388 fill_buffer(file_pos, buffer, buffer_size);
2391 return res;
2394 static bool word_wrap_setting(void)
2396 static const struct opt_items names[] = {
2397 {"On", -1},
2398 {"Off (Chop Words)", -1},
2401 return rb->set_option("Word Wrap", &prefs.word_mode, INT,
2402 names, 2, NULL);
2405 static bool line_mode_setting(void)
2407 static const struct opt_items names[] = {
2408 {"Normal", -1},
2409 {"Join Lines", -1},
2410 {"Expand Lines", -1},
2411 #ifdef HAVE_LCD_BITMAP
2412 {"Reflow Lines", -1},
2413 #endif
2416 return rb->set_option("Line Mode", &prefs.line_mode, INT, names,
2417 sizeof(names) / sizeof(names[0]), NULL);
2420 static bool view_mode_setting(void)
2422 static const struct opt_items names[] = {
2423 {"No (Narrow)", -1},
2424 {"Yes", -1},
2426 bool ret;
2427 ret = rb->set_option("Wide View", &prefs.view_mode, INT,
2428 names , 2, NULL);
2429 if (prefs.view_mode == NARROW)
2430 col = 0;
2431 calc_max_width();
2432 return ret;
2435 static bool scroll_mode_setting(void)
2437 static const struct opt_items names[] = {
2438 {"Scroll by Page", -1},
2439 {"Scroll by Line", -1},
2442 return rb->set_option("Scroll Mode", &prefs.scroll_mode, INT,
2443 names, 2, NULL);
2446 #ifdef HAVE_LCD_BITMAP
2447 static bool page_mode_setting(void)
2449 static const struct opt_items names[] = {
2450 {"No", -1},
2451 {"Yes", -1},
2454 return rb->set_option("Overlap Pages", &prefs.page_mode, INT,
2455 names, 2, NULL);
2458 static bool scrollbar_setting(void)
2460 static const struct opt_items names[] = {
2461 {"Off", -1},
2462 {"On", -1}
2465 return rb->set_option("Show Scrollbar", &prefs.scrollbar_mode, INT,
2466 names, 2, NULL);
2469 static bool header_setting(void)
2471 int len = (rb->global_settings->statusbar == STATUSBAR_TOP)? 4 : 2;
2472 struct opt_items names[len];
2474 names[0].string = "None";
2475 names[0].voice_id = -1;
2476 names[1].string = "File path";
2477 names[1].voice_id = -1;
2479 if (rb->global_settings->statusbar == STATUSBAR_TOP)
2481 names[2].string = "Status bar";
2482 names[2].voice_id = -1;
2483 names[3].string = "Both";
2484 names[3].voice_id = -1;
2487 return rb->set_option("Show Header", &prefs.header_mode, INT,
2488 names, len, NULL);
2491 static bool footer_setting(void)
2493 int len = (rb->global_settings->statusbar == STATUSBAR_BOTTOM)? 4 : 2;
2494 struct opt_items names[len];
2496 names[0].string = "None";
2497 names[0].voice_id = -1;
2498 names[1].string = "Page Num";
2499 names[1].voice_id = -1;
2501 if (rb->global_settings->statusbar == STATUSBAR_BOTTOM)
2503 names[2].string = "Status bar";
2504 names[2].voice_id = -1;
2505 names[3].string = "Both";
2506 names[3].voice_id = -1;
2509 return rb->set_option("Show Footer", &prefs.footer_mode, INT,
2510 names, len, NULL);
2513 static int font_comp(const void *a, const void *b)
2515 struct opt_items *pa;
2516 struct opt_items *pb;
2518 pa = (struct opt_items *)a;
2519 pb = (struct opt_items *)b;
2521 return rb->strcmp(pa->string, pb->string);
2524 static bool font_setting(void)
2526 int count = 0;
2527 DIR *dir;
2528 struct dirent *entry;
2529 int i = 0;
2530 int len;
2531 int new_font = 0;
2532 int old_font;
2533 bool res;
2534 int size = 0;
2536 dir = rb->opendir(FONT_DIR);
2537 if (!dir)
2539 rb->splash(HZ/2, "font dir does not access.");
2540 return false;
2543 while (1)
2545 entry = rb->readdir(dir);
2547 if (entry == NULL)
2548 break;
2550 len = rb->strlen(entry->d_name);
2551 if (len < 4 || rb->strcmp(entry->d_name + len-4, ".fnt"))
2552 continue;
2553 size += len-3;
2554 count++;
2556 rb->closedir(dir);
2558 struct opt_items names[count];
2559 unsigned char font_names[size];
2560 unsigned char *p = font_names;
2562 dir = rb->opendir(FONT_DIR);
2563 if (!dir)
2565 rb->splash(HZ/2, "font dir does not access.");
2566 return false;
2569 while (1)
2571 entry = rb->readdir(dir);
2573 if (entry == NULL)
2574 break;
2576 len = rb->strlen(entry->d_name);
2577 if (len < 4 || rb->strcmp(entry->d_name + len-4, ".fnt"))
2578 continue;
2580 rb->snprintf(p, len-3, "%s", entry->d_name);
2581 names[i].string = p;
2582 names[i].voice_id = -1;
2583 p += len-3;
2584 i++;
2585 if (i >= count)
2586 break;
2588 rb->closedir(dir);
2590 rb->qsort(names, count, sizeof(struct opt_items), font_comp);
2592 for (i = 0; i < count; i++)
2594 if (!rb->strcmp(names[i].string, prefs.font))
2596 new_font = i;
2597 break;
2600 old_font = new_font;
2602 res = rb->set_option("Select Font", &new_font, INT,
2603 names, count, NULL);
2605 if (new_font != old_font)
2607 rb->memset(prefs.font, 0, MAX_PATH);
2608 rb->snprintf(prefs.font, MAX_PATH, "%s", names[new_font].string);
2609 change_font(prefs.font);
2612 return res;
2614 #endif
2616 static bool autoscroll_speed_setting(void)
2618 return rb->set_int("Auto-scroll Speed", "", UNIT_INT,
2619 &prefs.autoscroll_speed, NULL, 1, 1, 10, NULL);
2622 MENUITEM_FUNCTION(encoding_item, 0, "Encoding", encoding_setting,
2623 NULL, NULL, Icon_NOICON);
2624 MENUITEM_FUNCTION(word_wrap_item, 0, "Word Wrap", word_wrap_setting,
2625 NULL, NULL, Icon_NOICON);
2626 MENUITEM_FUNCTION(line_mode_item, 0, "Line Mode", line_mode_setting,
2627 NULL, NULL, Icon_NOICON);
2628 MENUITEM_FUNCTION(view_mode_item, 0, "Wide View", view_mode_setting,
2629 NULL, NULL, Icon_NOICON);
2630 #ifdef HAVE_LCD_BITMAP
2631 MENUITEM_FUNCTION(scrollbar_item, 0, "Show Scrollbar", scrollbar_setting,
2632 NULL, NULL, Icon_NOICON);
2633 MENUITEM_FUNCTION(page_mode_item, 0, "Overlap Pages", page_mode_setting,
2634 NULL, NULL, Icon_NOICON);
2635 MENUITEM_FUNCTION(header_item, 0, "Show Header", header_setting,
2636 NULL, NULL, Icon_NOICON);
2637 MENUITEM_FUNCTION(footer_item, 0, "Show Footer", footer_setting,
2638 NULL, NULL, Icon_NOICON);
2639 MENUITEM_FUNCTION(font_item, 0, "Font", font_setting,
2640 NULL, NULL, Icon_NOICON);
2641 #endif
2642 MENUITEM_FUNCTION(scroll_mode_item, 0, "Scroll Mode", scroll_mode_setting,
2643 NULL, NULL, Icon_NOICON);
2644 MENUITEM_FUNCTION(autoscroll_speed_item, 0, "Auto-Scroll Speed",
2645 autoscroll_speed_setting, NULL, NULL, Icon_NOICON);
2646 MAKE_MENU(option_menu, "Viewer Options", NULL, Icon_NOICON,
2647 &encoding_item, &word_wrap_item, &line_mode_item, &view_mode_item,
2648 #ifdef HAVE_LCD_BITMAP
2649 &scrollbar_item, &page_mode_item, &header_item, &footer_item, &font_item,
2650 #endif
2651 &scroll_mode_item, &autoscroll_speed_item);
2653 static bool viewer_options_menu(bool is_global)
2655 bool result;
2656 struct preferences tmp_prefs;
2658 rb->memcpy(&tmp_prefs, &prefs, sizeof(struct preferences));
2660 result = (rb->do_menu(&option_menu, NULL, NULL, false) == MENU_ATTACHED_USB);
2662 if (!is_global && rb->memcmp(&tmp_prefs, &prefs, sizeof(struct preferences)))
2664 /* Show-scrollbar mode for current view-width mode */
2665 #ifdef HAVE_LCD_BITMAP
2666 init_need_scrollbar();
2667 init_header_and_footer();
2668 #endif
2669 calc_page();
2671 return result;
2674 static void viewer_menu(void)
2676 int result;
2678 MENUITEM_STRINGLIST(menu, "Viewer Menu", NULL,
2679 "Return", "Viewer Options",
2680 "Show Playback Menu", "Select Bookmark",
2681 "Global Settings", "Quit");
2683 result = rb->do_menu(&menu, NULL, NULL, false);
2684 switch (result)
2686 case 0: /* return */
2687 break;
2688 case 1: /* change settings */
2689 done = viewer_options_menu(false);
2690 break;
2691 case 2: /* playback control */
2692 playback_control(NULL);
2693 break;
2694 case 3: /* select bookmark */
2695 viewer_select_bookmark(viewer_add_last_read_bookmark());
2696 viewer_remove_last_read_bookmark();
2697 fill_buffer(file_pos, buffer, buffer_size);
2698 if (prefs.scroll_mode == PAGE && cline > 1)
2699 viewer_scroll_to_top_line();
2700 break;
2701 case 4: /* change global settings */
2703 struct preferences orig_prefs;
2705 rb->memcpy(&orig_prefs, &prefs, sizeof(struct preferences));
2706 if (!viewer_load_global_settings())
2707 viewer_default_preferences();
2708 done = viewer_options_menu(true);
2709 viewer_save_global_settings();
2710 rb->memcpy(&prefs, &orig_prefs, sizeof(struct preferences));
2712 break;
2713 case 5: /* quit */
2714 viewer_exit(NULL);
2715 done = true;
2716 break;
2718 viewer_draw(col);
2721 enum plugin_status plugin_start(const void* file)
2723 int button, i, ok;
2724 int lastbutton = BUTTON_NONE;
2725 bool autoscroll = false;
2726 long old_tick;
2728 old_tick = *rb->current_tick;
2730 /* get the plugin buffer */
2731 buffer = rb->plugin_get_buffer((size_t *)&buffer_size);
2732 if (buffer_size == 0)
2734 rb->splash(HZ, "buffer does not allocate !!");
2735 return PLUGIN_ERROR;
2737 block_size = buffer_size / 3;
2738 buffer_size = 3 * block_size;
2740 if (!file)
2741 return PLUGIN_ERROR;
2743 file_name = file;
2744 ok = viewer_init();
2745 if (!ok) {
2746 rb->splash(HZ, "Error opening file.");
2747 return PLUGIN_ERROR;
2750 viewer_load_settings(); /* load the preferences and bookmark */
2752 #if LCD_DEPTH > 1
2753 rb->lcd_set_backdrop(NULL);
2754 #endif
2756 viewer_draw(col);
2758 while (!done) {
2760 if(autoscroll)
2762 if(old_tick <= *rb->current_tick - (110-prefs.autoscroll_speed*10))
2764 viewer_scroll_down(true);
2765 viewer_draw(col);
2766 old_tick = *rb->current_tick;
2770 button = rb->button_get_w_tmo(HZ/10);
2772 switch (button) {
2773 case VIEWER_MENU:
2774 #ifdef VIEWER_MENU2
2775 case VIEWER_MENU2:
2776 #endif
2777 viewer_menu();
2778 break;
2780 case VIEWER_AUTOSCROLL:
2781 #ifdef VIEWER_AUTOSCROLL_PRE
2782 if (lastbutton != VIEWER_AUTOSCROLL_PRE)
2783 break;
2784 #endif
2785 autoscroll = !autoscroll;
2786 break;
2788 case VIEWER_PAGE_UP:
2789 case VIEWER_PAGE_UP | BUTTON_REPEAT:
2790 #ifdef VIEWER_PAGE_UP2
2791 case VIEWER_PAGE_UP2:
2792 case VIEWER_PAGE_UP2 | BUTTON_REPEAT:
2793 #endif
2794 if (prefs.scroll_mode == PAGE)
2796 /* Page up */
2797 #ifdef HAVE_LCD_BITMAP
2798 for (i = prefs.page_mode==OVERLAP? 1:0; i < display_lines; i++)
2799 #else
2800 for (i = 0; i < display_lines; i++)
2801 #endif
2802 viewer_scroll_up();
2804 else
2805 viewer_scroll_up();
2806 old_tick = *rb->current_tick;
2807 viewer_draw(col);
2808 break;
2810 case VIEWER_PAGE_DOWN:
2811 case VIEWER_PAGE_DOWN | BUTTON_REPEAT:
2812 #ifdef VIEWER_PAGE_DOWN2
2813 case VIEWER_PAGE_DOWN2:
2814 case VIEWER_PAGE_DOWN2 | BUTTON_REPEAT:
2815 #endif
2816 if (prefs.scroll_mode == PAGE)
2818 /* Page down */
2819 if (next_screen_ptr != NULL)
2821 screen_top_ptr = next_screen_to_draw_ptr;
2822 if (cpage < MAX_PAGE)
2823 cpage++;
2826 else
2827 viewer_scroll_down(autoscroll);
2828 old_tick = *rb->current_tick;
2829 viewer_draw(col);
2830 break;
2832 case VIEWER_SCREEN_LEFT:
2833 case VIEWER_SCREEN_LEFT | BUTTON_REPEAT:
2834 if (prefs.view_mode == WIDE) {
2835 /* Screen left */
2836 col -= draw_columns;
2837 col = col_limit(col);
2839 else { /* prefs.view_mode == NARROW */
2840 /* Top of file */
2841 viewer_top();
2844 viewer_draw(col);
2845 break;
2847 case VIEWER_SCREEN_RIGHT:
2848 case VIEWER_SCREEN_RIGHT | BUTTON_REPEAT:
2849 if (prefs.view_mode == WIDE) {
2850 /* Screen right */
2851 col += draw_columns;
2852 col = col_limit(col);
2854 else { /* prefs.view_mode == NARROW */
2855 /* Bottom of file */
2856 viewer_bottom();
2859 viewer_draw(col);
2860 break;
2862 #ifdef VIEWER_LINE_UP
2863 case VIEWER_LINE_UP:
2864 case VIEWER_LINE_UP | BUTTON_REPEAT:
2865 /* Scroll up one line */
2866 viewer_scroll_up();
2867 old_tick = *rb->current_tick;
2868 viewer_draw(col);
2869 break;
2871 case VIEWER_LINE_DOWN:
2872 case VIEWER_LINE_DOWN | BUTTON_REPEAT:
2873 /* Scroll down one line */
2874 viewer_scroll_down(autoscroll);
2875 increment_current_line();
2876 old_tick = *rb->current_tick;
2877 viewer_draw(col);
2878 break;
2879 #endif
2880 #ifdef VIEWER_COLUMN_LEFT
2881 case VIEWER_COLUMN_LEFT:
2882 case VIEWER_COLUMN_LEFT | BUTTON_REPEAT:
2883 if (prefs.view_mode == WIDE) {
2884 /* Scroll left one column */
2885 col -= glyph_width('o');
2886 col = col_limit(col);
2887 viewer_draw(col);
2889 break;
2891 case VIEWER_COLUMN_RIGHT:
2892 case VIEWER_COLUMN_RIGHT | BUTTON_REPEAT:
2893 if (prefs.view_mode == WIDE) {
2894 /* Scroll right one column */
2895 col += glyph_width('o');
2896 col = col_limit(col);
2897 viewer_draw(col);
2899 break;
2900 #endif
2902 #ifdef VIEWER_RC_QUIT
2903 case VIEWER_RC_QUIT:
2904 #endif
2905 case VIEWER_QUIT:
2906 #ifdef VIEWER_QUIT2
2907 case VIEWER_QUIT2:
2908 #endif
2909 viewer_exit(NULL);
2910 done = true;
2911 break;
2913 case VIEWER_BOOKMARK:
2915 int idx = viewer_find_bookmark(cpage, cline);
2917 if (idx < 0)
2919 if (bookmark_count >= MAX_BOOKMARKS-1)
2920 rb->splash(HZ/2, "No more add bookmark.");
2921 else
2923 viewer_add_bookmark();
2924 rb->splash(HZ/2, "Bookmark add.");
2927 else
2929 viewer_remove_bookmark(idx);
2930 rb->splash(HZ/2, "Bookmark remove.");
2932 viewer_draw(col);
2934 break;
2936 default:
2937 if (rb->default_event_handler_ex(button, viewer_exit, NULL)
2938 == SYS_USB_CONNECTED)
2939 return PLUGIN_USB_CONNECTED;
2940 break;
2942 if (button != BUTTON_NONE)
2944 lastbutton = button;
2945 rb->yield();
2948 return PLUGIN_OK;