Use better names for hotkey related constants; add somecomments (FS#11191)
[kugel-rb.git] / apps / plugins / viewer.c
blob890ed629f405531f07fd4a27f0bb04bcefabd6b5
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" /* header="TVGS" */
56 #define GLOBAL_SETTINGS_H_SIZE 5
57 #define GLOBAL_SETTINGS_VERSION 0x32 /* version=2 */
58 #define GLOBAL_SETTINGS_FIRST_VERSION 0x31
60 /* preferences and bookmarks at each file
61 * binary file, so dont use .cfg
63 * setting file format
65 * part byte count
66 * --------------------------------
67 * 'TVS' 3
68 * version 1
69 * file count 2
70 * [1st file]
71 * file path MAX_PATH
72 * next file pos 2
73 * [preferences]
74 * word_mode 1
75 * line_mode 1
76 * view_mode 1
77 * alignment 1
78 * encoding 1
79 * scrollbar_mode 1
80 * need_scrollbar 1
81 * page_mode 1
82 * header_mode 1
83 * footer_mode 1
84 * scroll_mode 1
85 * autoscroll_speed 1
86 * font name MAX_PATH
87 * bookmark count 1
88 * [1st bookmark]
89 * file_position 4
90 * page 2
91 * line 1
92 * flag 1
93 * [2nd bookmark]
94 * ...
95 * [last bookmark]
96 * [2nd file]
97 * ...
98 * [last file]
100 #define SETTINGS_FILE VIEWERS_DIR "/viewer_file.dat"
102 /* temporary file */
103 #define SETTINGS_TMP_FILE VIEWERS_DIR "/viewer_file.tmp"
105 #define SETTINGS_HEADER "\x54\x56\x53" /* header="TVS" */
106 #define SETTINGS_H_SIZE 4
107 #define SETTINGS_VERSION 0x33 /* version=3 */
108 #define SETTINGS_FIRST_VERSION 0x32
110 #define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */
111 #define NARROW_MAX_COLUMNS 64 /* Max displayable string len [narrow] (over-estimate) */
112 #define WIDE_MAX_COLUMNS 128 /* Max displayable string len [wide] (over-estimate) */
113 #define MAX_WIDTH 910 /* Max line length in WIDE mode */
114 #define READ_PREV_ZONE (block_size*9/10) /* Arbitrary number less than SMALL_BLOCK_SIZE */
115 #define SMALL_BLOCK_SIZE block_size /* Smallest file chunk we will read */
116 #define LARGE_BLOCK_SIZE (block_size << 1) /* Preferable size of file chunk to read */
117 #define TOP_SECTOR buffer
118 #define MID_SECTOR (buffer + SMALL_BLOCK_SIZE)
119 #define BOTTOM_SECTOR (buffer + (SMALL_BLOCK_SIZE << 1))
120 #undef SCROLLBAR_WIDTH
121 #define SCROLLBAR_WIDTH rb->global_settings->scrollbar_width
122 #define MAX_PAGE 9999
124 #define BOOKMARK_SIZE 8
125 #define MAX_BOOKMARKS 10 /* user setting bookmarks + last read page */
127 #define BOOKMARK_LAST 1
128 #define BOOKMARK_USER 2
130 #ifndef HAVE_LCD_BITMAP
131 #define BOOKMARK_ICON "\xee\x84\x81\x00"
132 #endif
134 #define PREFERENCES_SIZE (12 + MAX_PATH)
136 /* Out-Of-Bounds test for any pointer to data in the buffer */
137 #define BUFFER_OOB(p) ((p) < buffer || (p) >= buffer_end)
139 /* Does the buffer contain the beginning of the file? */
140 #define BUFFER_BOF() (file_pos==0)
142 /* Does the buffer contain the end of the file? */
143 #define BUFFER_EOF() (file_size-file_pos <= buffer_size)
145 /* Formula for the endpoint address outside of buffer data */
146 #define BUFFER_END() \
147 ((BUFFER_EOF()) ? (file_size-file_pos+buffer) : (buffer+buffer_size))
149 /* Is the entire file being shown in one screen? */
150 #define ONE_SCREEN_FITS_ALL() \
151 (next_screen_ptr==NULL && screen_top_ptr==buffer && BUFFER_BOF())
153 /* Is a scrollbar called for on the current screen? */
154 #define NEED_SCROLLBAR() \
155 ((!(ONE_SCREEN_FITS_ALL())) && (prefs.scrollbar_mode==SB_ON))
157 /* variable button definitions */
159 /* Recorder keys */
160 #if CONFIG_KEYPAD == RECORDER_PAD
161 #define VIEWER_QUIT BUTTON_OFF
162 #define VIEWER_PAGE_UP BUTTON_UP
163 #define VIEWER_PAGE_DOWN BUTTON_DOWN
164 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
165 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
166 #define VIEWER_MENU BUTTON_F1
167 #define VIEWER_AUTOSCROLL BUTTON_PLAY
168 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
169 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
170 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
171 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
172 #define VIEWER_BOOKMARK BUTTON_F2
174 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
175 #define VIEWER_QUIT BUTTON_OFF
176 #define VIEWER_PAGE_UP BUTTON_UP
177 #define VIEWER_PAGE_DOWN BUTTON_DOWN
178 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
179 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
180 #define VIEWER_MENU BUTTON_F1
181 #define VIEWER_AUTOSCROLL BUTTON_SELECT
182 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
183 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
184 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
185 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
186 #define VIEWER_BOOKMARK BUTTON_F2
188 /* Ondio keys */
189 #elif CONFIG_KEYPAD == ONDIO_PAD
190 #define VIEWER_QUIT BUTTON_OFF
191 #define VIEWER_PAGE_UP BUTTON_UP
192 #define VIEWER_PAGE_DOWN BUTTON_DOWN
193 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
194 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
195 #define VIEWER_MENU (BUTTON_MENU|BUTTON_REPEAT)
196 #define VIEWER_AUTOSCROLL_PRE BUTTON_MENU
197 #define VIEWER_AUTOSCROLL (BUTTON_MENU|BUTTON_REL)
198 #define VIEWER_BOOKMARK (BUTTON_MENU|BUTTON_OFF)
200 /* Player keys */
201 #elif CONFIG_KEYPAD == PLAYER_PAD
202 #define VIEWER_QUIT BUTTON_STOP
203 #define VIEWER_PAGE_UP BUTTON_LEFT
204 #define VIEWER_PAGE_DOWN BUTTON_RIGHT
205 #define VIEWER_SCREEN_LEFT (BUTTON_ON|BUTTON_LEFT)
206 #define VIEWER_SCREEN_RIGHT (BUTTON_ON|BUTTON_RIGHT)
207 #define VIEWER_MENU BUTTON_MENU
208 #define VIEWER_AUTOSCROLL BUTTON_PLAY
209 #define VIEWER_BOOKMARK BUTTON_ON
211 /* iRiver H1x0 && H3x0 keys */
212 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
213 (CONFIG_KEYPAD == IRIVER_H300_PAD)
214 #define VIEWER_QUIT BUTTON_OFF
215 #define VIEWER_PAGE_UP BUTTON_UP
216 #define VIEWER_PAGE_DOWN BUTTON_DOWN
217 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
218 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
219 #define VIEWER_MENU BUTTON_MODE
220 #define VIEWER_AUTOSCROLL BUTTON_SELECT
221 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
222 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
223 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
224 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
225 #define VIEWER_BOOKMARK (BUTTON_ON | BUTTON_SELECT)
227 #define VIEWER_RC_QUIT BUTTON_RC_STOP
229 /* iPods */
230 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
231 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
232 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
233 #define VIEWER_QUIT_PRE BUTTON_SELECT
234 #define VIEWER_QUIT (BUTTON_SELECT | BUTTON_MENU)
235 #define VIEWER_PAGE_UP BUTTON_SCROLL_BACK
236 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_FWD
237 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
238 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
239 #define VIEWER_MENU BUTTON_MENU
240 #define VIEWER_AUTOSCROLL BUTTON_PLAY
241 #define VIEWER_BOOKMARK BUTTON_SELECT
243 /* iFP7xx keys */
244 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
245 #define VIEWER_QUIT BUTTON_PLAY
246 #define VIEWER_PAGE_UP BUTTON_UP
247 #define VIEWER_PAGE_DOWN BUTTON_DOWN
248 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
249 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
250 #define VIEWER_MENU BUTTON_MODE
251 #define VIEWER_AUTOSCROLL BUTTON_SELECT
252 #define VIEWER_BOOKMARK (BUTTON_LEFT|BUTTON_SELECT)
254 /* iAudio X5 keys */
255 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
256 #define VIEWER_QUIT BUTTON_POWER
257 #define VIEWER_PAGE_UP BUTTON_UP
258 #define VIEWER_PAGE_DOWN BUTTON_DOWN
259 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
260 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
261 #define VIEWER_MENU BUTTON_SELECT
262 #define VIEWER_AUTOSCROLL BUTTON_PLAY
263 #define VIEWER_BOOKMARK BUTTON_REC
265 /* GIGABEAT keys */
266 #elif CONFIG_KEYPAD == GIGABEAT_PAD
267 #define VIEWER_QUIT BUTTON_POWER
268 #define VIEWER_PAGE_UP BUTTON_UP
269 #define VIEWER_PAGE_DOWN BUTTON_DOWN
270 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
271 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
272 #define VIEWER_MENU BUTTON_MENU
273 #define VIEWER_AUTOSCROLL BUTTON_A
274 #define VIEWER_BOOKMARK BUTTON_SELECT
276 /* Sansa E200 keys */
277 #elif CONFIG_KEYPAD == SANSA_E200_PAD
278 #define VIEWER_QUIT BUTTON_POWER
279 #define VIEWER_PAGE_UP BUTTON_UP
280 #define VIEWER_PAGE_DOWN BUTTON_DOWN
281 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
282 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
283 #define VIEWER_MENU BUTTON_SELECT
284 #define VIEWER_AUTOSCROLL BUTTON_REC
285 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
286 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
287 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
289 /* Sansa Fuze keys */
290 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
291 #define VIEWER_QUIT (BUTTON_HOME|BUTTON_REPEAT)
292 #define VIEWER_PAGE_UP BUTTON_UP
293 #define VIEWER_PAGE_DOWN BUTTON_DOWN
294 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
295 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
296 #define VIEWER_MENU BUTTON_SELECT|BUTTON_REPEAT
297 #define VIEWER_AUTOSCROLL BUTTON_SELECT|BUTTON_DOWN
298 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
299 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
300 #define VIEWER_BOOKMARK BUTTON_SELECT
302 /* Sansa C200 keys */
303 #elif CONFIG_KEYPAD == SANSA_C200_PAD
304 #define VIEWER_QUIT BUTTON_POWER
305 #define VIEWER_PAGE_UP BUTTON_VOL_UP
306 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
307 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
308 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
309 #define VIEWER_MENU BUTTON_SELECT
310 #define VIEWER_AUTOSCROLL BUTTON_REC
311 #define VIEWER_LINE_UP BUTTON_UP
312 #define VIEWER_LINE_DOWN BUTTON_DOWN
313 #define VIEWER_BOOKMARK (BUTTON_DOWN | BUTTON_SELECT)
315 /* Sansa Clip keys */
316 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
317 #define VIEWER_QUIT BUTTON_POWER
318 #define VIEWER_PAGE_UP BUTTON_VOL_UP
319 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
320 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
321 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
322 #define VIEWER_MENU BUTTON_SELECT
323 #define VIEWER_AUTOSCROLL BUTTON_HOME
324 #define VIEWER_LINE_UP BUTTON_UP
325 #define VIEWER_LINE_DOWN BUTTON_DOWN
326 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
328 /* Sansa M200 keys */
329 #elif CONFIG_KEYPAD == SANSA_M200_PAD
330 #define VIEWER_QUIT BUTTON_POWER
331 #define VIEWER_PAGE_UP BUTTON_VOL_UP
332 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
333 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
334 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
335 #define VIEWER_MENU (BUTTON_SELECT | BUTTON_UP)
336 #define VIEWER_AUTOSCROLL (BUTTON_SELECT | BUTTON_REL)
337 #define VIEWER_LINE_UP BUTTON_UP
338 #define VIEWER_LINE_DOWN BUTTON_DOWN
339 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
341 /* iriver H10 keys */
342 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
343 #define VIEWER_QUIT BUTTON_POWER
344 #define VIEWER_PAGE_UP BUTTON_SCROLL_UP
345 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_DOWN
346 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
347 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
348 #define VIEWER_MENU BUTTON_REW
349 #define VIEWER_AUTOSCROLL BUTTON_PLAY
350 #define VIEWER_BOOKMARK BUTTON_FF
352 /*M-Robe 500 keys */
353 #elif CONFIG_KEYPAD == MROBE500_PAD
354 #define VIEWER_QUIT BUTTON_POWER
355 #define VIEWER_PAGE_UP BUTTON_RC_PLAY
356 #define VIEWER_PAGE_DOWN BUTTON_RC_DOWN
357 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
358 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
359 #define VIEWER_MENU BUTTON_RC_HEART
360 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
361 #define VIEWER_BOOKMARK BUTTON_CENTER
363 /*Gigabeat S keys */
364 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
365 #define VIEWER_QUIT BUTTON_BACK
366 #define VIEWER_PAGE_UP BUTTON_PREV
367 #define VIEWER_PAGE_DOWN BUTTON_NEXT
368 #define VIEWER_SCREEN_LEFT (BUTTON_PLAY | BUTTON_LEFT)
369 #define VIEWER_SCREEN_RIGHT (BUTTON_PLAY | BUTTON_RIGHT)
370 #define VIEWER_MENU BUTTON_MENU
371 #define VIEWER_AUTOSCROLL_PRE BUTTON_PLAY
372 #define VIEWER_AUTOSCROLL (BUTTON_PLAY|BUTTON_REL)
373 #define VIEWER_LINE_UP BUTTON_UP
374 #define VIEWER_LINE_DOWN BUTTON_DOWN
375 #define VIEWER_COLUMN_LEFT BUTTON_LEFT
376 #define VIEWER_COLUMN_RIGHT BUTTON_RIGHT
377 #define VIEWER_BOOKMARK BUTTON_SELECT
379 /*M-Robe 100 keys */
380 #elif CONFIG_KEYPAD == MROBE100_PAD
381 #define VIEWER_QUIT BUTTON_POWER
382 #define VIEWER_PAGE_UP BUTTON_UP
383 #define VIEWER_PAGE_DOWN BUTTON_DOWN
384 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
385 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
386 #define VIEWER_MENU BUTTON_MENU
387 #define VIEWER_AUTOSCROLL BUTTON_DISPLAY
388 #define VIEWER_BOOKMARK BUTTON_SELECT
390 /* iAUdio M3 keys */
391 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
392 #define VIEWER_QUIT BUTTON_REC
393 #define VIEWER_PAGE_UP BUTTON_RC_VOL_UP
394 #define VIEWER_PAGE_DOWN BUTTON_RC_VOL_DOWN
395 #define VIEWER_SCREEN_LEFT BUTTON_RC_REW
396 #define VIEWER_SCREEN_RIGHT BUTTON_RC_FF
397 #define VIEWER_MENU BUTTON_RC_MENU
398 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
399 #define VIEWER_RC_QUIT BUTTON_RC_REC
400 #define VIEWER_BOOKMARK BUTTON_RC_PLAY
402 /* Cowon D2 keys */
403 #elif CONFIG_KEYPAD == COWON_D2_PAD
404 #define VIEWER_QUIT BUTTON_POWER
405 #define VIEWER_MENU BUTTON_MENU
406 #define VIEWER_PAGE_UP BUTTON_MINUS
407 #define VIEWER_PAGE_DOWN BUTTON_PLUS
408 #define VIEWER_BOOKMARK (BUTTON_MENU|BUTTON_PLUS)
410 #elif CONFIG_KEYPAD == IAUDIO67_PAD
411 #define VIEWER_QUIT BUTTON_POWER
412 #define VIEWER_PAGE_UP BUTTON_VOLUP
413 #define VIEWER_PAGE_DOWN BUTTON_VOLDOWN
414 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
415 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
416 #define VIEWER_MENU BUTTON_MENU
417 #define VIEWER_AUTOSCROLL BUTTON_PLAY
418 #define VIEWER_RC_QUIT BUTTON_STOP
419 #define VIEWER_BOOKMARK (BUTTON_LEFT|BUTTON_PLAY)
421 /* Creative Zen Vision:M keys */
422 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
423 #define VIEWER_QUIT BUTTON_BACK
424 #define VIEWER_PAGE_UP BUTTON_UP
425 #define VIEWER_PAGE_DOWN BUTTON_DOWN
426 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
427 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
428 #define VIEWER_MENU BUTTON_MENU
429 #define VIEWER_AUTOSCROLL BUTTON_SELECT
430 #define VIEWER_BOOKMARK BUTTON_PLAY
432 /* Philips HDD1630 keys */
433 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
434 #define VIEWER_QUIT BUTTON_POWER
435 #define VIEWER_PAGE_UP BUTTON_UP
436 #define VIEWER_PAGE_DOWN BUTTON_DOWN
437 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
438 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
439 #define VIEWER_MENU BUTTON_MENU
440 #define VIEWER_AUTOSCROLL BUTTON_VIEW
441 #define VIEWER_BOOKMARK BUTTON_SELECT
443 /* Philips SA9200 keys */
444 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
445 #define VIEWER_QUIT BUTTON_POWER
446 #define VIEWER_PAGE_UP BUTTON_UP
447 #define VIEWER_PAGE_DOWN BUTTON_DOWN
448 #define VIEWER_SCREEN_LEFT BUTTON_PREV
449 #define VIEWER_SCREEN_RIGHT BUTTON_NEXT
450 #define VIEWER_MENU BUTTON_MENU
451 #define VIEWER_AUTOSCROLL BUTTON_PLAY
452 #define VIEWER_BOOKMARK BUTTON_RIGHT
454 /* Onda VX747 keys */
455 #elif CONFIG_KEYPAD == ONDAVX747_PAD
456 #define VIEWER_QUIT BUTTON_POWER
457 #define VIEWER_MENU BUTTON_MENU
458 #define VIEWER_BOOKMARK (BUTTON_RIGHT|BUTTON_POWER)
460 /* Onda VX777 keys */
461 #elif CONFIG_KEYPAD == ONDAVX777_PAD
462 #define VIEWER_QUIT BUTTON_POWER
463 #define VIEWER_BOOKMARK (BUTTON_RIGHT|BUTTON_POWER)
465 /* SAMSUNG YH-820 / YH-920 / YH-925 keys */
466 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
467 #define VIEWER_QUIT BUTTON_REC
468 #define VIEWER_PAGE_UP BUTTON_UP
469 #define VIEWER_PAGE_DOWN BUTTON_DOWN
470 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
471 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
472 #define VIEWER_MENU BUTTON_PLAY
473 #define VIEWER_AUTOSCROLL BUTTON_REW
474 #define VIEWER_BOOKMARK BUTTON_FFWD
476 /* Packard Bell Vibe 500 keys */
477 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
478 #define VIEWER_QUIT BUTTON_REC
479 #define VIEWER_PAGE_UP BUTTON_OK
480 #define VIEWER_PAGE_DOWN BUTTON_CANCEL
481 #define VIEWER_LINE_UP BUTTON_UP
482 #define VIEWER_LINE_DOWN BUTTON_DOWN
483 #define VIEWER_SCREEN_LEFT BUTTON_PREV
484 #define VIEWER_SCREEN_RIGHT BUTTON_NEXT
485 #define VIEWER_MENU BUTTON_MENU
486 #define VIEWER_AUTOSCROLL BUTTON_PLAY
487 #define VIEWER_BOOKMARK BUTTON_POWER
489 #else
490 #error No keymap defined!
491 #endif
493 #ifdef HAVE_TOUCHSCREEN
494 #ifdef VIEWER_QUIT
495 #define VIEWER_QUIT2 BUTTON_TOPLEFT
496 #else
497 #define VIEWER_QUIT BUTTON_TOPLEFT
498 #endif
499 #ifdef VIEWER_PAGE_UP
500 #define VIEWER_PAGE_UP2 BUTTON_TOPMIDDLE
501 #else
502 #define VIEWER_PAGE_UP BUTTON_TOPMIDDLE
503 #endif
504 #ifdef VIEWER_PAGE_DOWN
505 #define VIEWER_PAGE_DOWN2 BUTTON_BOTTOMMIDDLE
506 #else
507 #define VIEWER_PAGE_DOWN BUTTON_BOTTOMMIDDLE
508 #endif
509 #ifndef VIEWER_SCREEN_LEFT
510 #define VIEWER_SCREEN_LEFT BUTTON_MIDLEFT
511 #endif
512 #ifndef VIEWER_SCREEN_RIGHT
513 #define VIEWER_SCREEN_RIGHT BUTTON_MIDRIGHT
514 #endif
515 #ifdef VIEWER_MENU
516 #define VIEWER_MENU2 BUTTON_TOPRIGHT
517 #else
518 #define VIEWER_MENU BUTTON_TOPRIGHT
519 #endif
520 #ifndef VIEWER_AUTOSCROLL
521 #define VIEWER_AUTOSCROLL BUTTON_CENTER
522 #endif
523 #endif
525 /* stuff for the bookmarking */
526 struct bookmark_info {
527 long file_position;
528 int page;
529 int line;
530 unsigned char flag;
533 struct preferences {
534 enum {
535 WRAP=0,
536 CHOP,
537 } word_mode;
539 enum {
540 NORMAL=0,
541 JOIN,
542 EXPAND,
543 REFLOW, /* won't be set on charcell LCD, must be last */
544 } line_mode;
546 enum {
547 NARROW=0,
548 WIDE,
549 } view_mode;
551 enum {
552 LEFT=0,
553 RIGHT,
554 } alignment;
556 enum codepages encoding;
558 enum {
559 SB_OFF=0,
560 SB_ON,
561 } scrollbar_mode;
562 bool need_scrollbar;
564 enum {
565 NO_OVERLAP=0,
566 OVERLAP,
567 } page_mode;
569 enum {
570 HD_NONE = 0,
571 HD_PATH,
572 HD_SBAR,
573 HD_BOTH,
574 } header_mode;
576 enum {
577 FT_NONE = 0,
578 FT_PAGE,
579 FT_SBAR,
580 FT_BOTH,
581 } footer_mode;
583 enum {
584 PAGE=0,
585 LINE,
586 } scroll_mode;
588 int autoscroll_speed;
590 unsigned char font[MAX_PATH];
593 enum {
594 VIEWER_FONT_MENU = 0,
595 VIEWER_FONT_TEXT,
598 struct preferences prefs;
599 struct preferences old_prefs;
601 static unsigned char *buffer;
602 static long buffer_size;
603 static long block_size = 0x1000;
604 static unsigned char line_break[] = {0,0x20,9,0xB,0xC,'-'};
605 static int display_columns; /* number of (pixel) columns on the display */
606 static int display_lines; /* number of lines on the display */
607 static int draw_columns; /* number of (pixel) columns available for text */
608 static int par_indent_spaces; /* number of spaces to indent first paragraph */
609 static int fd;
610 static const char *file_name;
611 static long file_size;
612 static long start_position; /* position in the file after the viewer is started */
613 static bool mac_text;
614 static long file_pos; /* Position of the top of the buffer in the file */
615 static long last_file_pos;
616 static unsigned char *buffer_end; /*Set to BUFFER_END() when file_pos changes*/
617 static int max_line_len;
618 static int max_width;
619 static int max_columns;
620 static int cline = 1;
621 static int cpage = 1;
622 static int lpage = 0;
623 static unsigned char *screen_top_ptr;
624 static unsigned char *next_screen_ptr;
625 static unsigned char *next_screen_to_draw_ptr;
626 static unsigned char *next_line_ptr;
627 static unsigned char *last_screen_top_ptr = NULL;
628 #ifdef HAVE_LCD_BITMAP
629 static struct font *pf;
630 static int header_height = 0;
631 static int footer_height = 0;
632 #endif
633 struct bookmark_info bookmarks[MAX_BOOKMARKS];
634 static int bookmark_count;
636 /* UTF-8 BOM */
637 #define BOM "\xef\xbb\xbf"
638 #define BOM_SIZE 3
640 static bool is_bom = false;
642 /* calculate the width of a UCS character (zero width for diacritics) */
643 static int glyph_width(unsigned short ch)
645 if (ch == 0)
646 ch = ' ';
648 #ifdef HAVE_LCD_BITMAP
649 if (rb->is_diacritic(ch, NULL))
650 return 0;
652 return rb->font_get_width(pf, ch);
653 #else
654 return 1;
655 #endif
658 /* get UCS character from string */
659 static unsigned char* get_ucs(const unsigned char* str, unsigned short* ch)
661 unsigned char utf8_tmp[6];
662 int count;
664 if (prefs.encoding == UTF_8)
665 return (unsigned char*)rb->utf8decode(str, ch);
667 count = BUFFER_OOB(str+2)? 1:2;
668 rb->iso_decode(str, utf8_tmp, prefs.encoding, count);
669 rb->utf8decode(utf8_tmp, ch);
671 /* return a pointer after the parsed section of the string */
672 #ifdef HAVE_LCD_BITMAP
673 if (prefs.encoding >= SJIS && *str >= 0x80
674 && !(prefs.encoding == SJIS && *str > 0xA0 && *str < 0xE0))
675 return (unsigned char*)str+2;
676 else
677 #endif
678 return (unsigned char*)str+1;
681 /* decode UCS string into UTF-8 string */
682 static unsigned char *decode2utf8(const unsigned char *src, unsigned char *dst,
683 int skip_width, int disp_width)
685 unsigned short ch;
686 const unsigned char *oldstr;
687 const unsigned char *str = src;
688 unsigned char *utf8 = dst;
689 int width = 0;
691 /* skip the skip_width */
692 while (*str != '\0')
694 oldstr = str;
695 str = get_ucs(oldstr, &ch);
696 width += glyph_width(ch);
697 if (width > skip_width)
699 str = oldstr;
700 break;
704 /* decode until string end or disp_width reached */
705 width = 0;
706 while(*str != '\0')
708 str = get_ucs(str, &ch);
709 width += glyph_width(ch);
710 if (width > disp_width)
711 break;
713 utf8 = rb->utf8encode(ch, utf8);
716 /* return a pointer after the dst string ends */
717 return utf8;
720 /* set max_columns and max_width */
721 static void calc_max_width(void)
723 if (prefs.view_mode == NARROW)
725 max_columns = NARROW_MAX_COLUMNS;
726 max_width = draw_columns;
728 else
730 max_columns = WIDE_MAX_COLUMNS;
731 max_width = 2 * draw_columns;
735 static bool done = false;
736 static int col = 0;
738 static inline void advance_conters(unsigned short ch, int* k, int* width)
740 #ifdef HAVE_LCD_BITMAP
741 /* diacritics do not count */
742 if (rb->is_diacritic(ch, NULL))
743 return;
744 #endif
746 *width += glyph_width(ch);
747 (*k)++;
750 static inline bool line_is_full(int k, int width)
752 return ((k >= max_columns - 1) || (width >= max_width));
755 static unsigned char* crop_at_width(const unsigned char* p)
757 int k,width;
758 unsigned short ch;
759 const unsigned char *oldp = p;
761 k=width=0;
763 while (!line_is_full(k, width)) {
764 oldp = p;
765 if (BUFFER_OOB(p))
766 break;
767 p = get_ucs(p, &ch);
768 advance_conters(ch, &k, &width);
771 return (unsigned char*)oldp;
774 static unsigned char* find_first_feed(const unsigned char* p, int size)
776 int s = 0;
777 unsigned short ch;
778 const unsigned char *oldp = p;
780 while(s <= size)
782 if (*p == 0)
783 return (unsigned char*)p;
784 oldp = p;
785 p = get_ucs(p, &ch);
786 s += (p - oldp);
789 return NULL;
792 static unsigned char* find_last_feed(const unsigned char* p, int size)
794 int i;
796 for (i=size-1; i>=0; i--)
797 if (p[i] == 0)
798 return (unsigned char*) p+i;
800 return NULL;
803 static unsigned char* find_last_space(const unsigned char* p, int size)
805 int i, j, k;
807 k = (prefs.line_mode==JOIN) || (prefs.line_mode==REFLOW) ? 0:1;
809 i = size;
810 if (!BUFFER_OOB(&p[i]))
811 for (j=k; j < ((int) sizeof(line_break)) - 1; j++) {
812 if (p[i] == line_break[j])
813 return (unsigned char*) p+i;
816 if (prefs.word_mode == WRAP) {
817 for (i=size-1; i>=0; i--) {
818 for (j=k; j < (int) sizeof(line_break) - 1; j++) {
819 if (p[i] == line_break[j])
820 return (unsigned char*) p+i;
825 return NULL;
828 static unsigned char* find_next_line(const unsigned char* cur_line, bool *is_short)
830 const unsigned char *next_line = NULL;
831 int size, i, j, j_next, j_prev, k, width, search_len, spaces, newlines;
832 bool first_chars;
833 unsigned short ch;
835 if (is_short != NULL)
836 *is_short = true;
838 if BUFFER_OOB(cur_line)
839 return NULL;
841 if (prefs.view_mode == WIDE) {
842 search_len = MAX_WIDTH;
844 else { /* prefs.view_mode == NARROW */
845 search_len = crop_at_width(cur_line) - cur_line;
848 size = BUFFER_OOB(cur_line+search_len) ? buffer_end-cur_line : search_len;
850 if ((prefs.line_mode == JOIN) || (prefs.line_mode == REFLOW)) {
851 /* Need to scan ahead and possibly increase search_len and size,
852 or possibly set next_line at second hard return in a row. */
853 next_line = NULL;
854 first_chars=true;
855 j_next=j=k=width=spaces=newlines=0;
856 while (1) {
857 const unsigned char *p, *oldp;
859 j_prev = j;
860 j = j_next;
862 if (BUFFER_OOB(cur_line+j))
863 return NULL;
864 if (line_is_full(k, width)) {
865 size = search_len = j_prev;
866 break;
869 oldp = p = &cur_line[j];
870 p = get_ucs(p, &ch);
871 j_next = j + (p - oldp);
873 switch (ch) {
874 case ' ':
875 if (prefs.line_mode == REFLOW) {
876 if (newlines > 0) {
877 size = j;
878 next_line = cur_line + size;
879 return (unsigned char*) next_line;
881 if (j==0) /* i=1 is intentional */
882 for (i=0; i<par_indent_spaces; i++)
883 advance_conters(' ', &k, &width);
885 if (!first_chars) spaces++;
886 break;
888 case 0:
889 if (newlines > 0) {
890 size = j;
891 next_line = cur_line + size - spaces;
892 if (next_line != cur_line)
893 return (unsigned char*) next_line;
894 break;
897 newlines++;
898 size += spaces -1;
899 if (BUFFER_OOB(cur_line+size) || size > 2*search_len)
900 return NULL;
901 search_len = size;
902 spaces = first_chars? 0:1;
903 break;
905 default:
906 if (prefs.line_mode==JOIN || newlines>0) {
907 while (spaces) {
908 spaces--;
909 advance_conters(' ', &k, &width);
910 if (line_is_full(k, width)) {
911 size = search_len = j;
912 break;
915 newlines=0;
916 } else if (spaces) {
917 /* REFLOW, multiple spaces between words: count only
918 * one. If more are needed, they will be added
919 * while drawing. */
920 search_len = size;
921 spaces=0;
922 advance_conters(' ', &k, &width);
923 if (line_is_full(k, width)) {
924 size = search_len = j;
925 break;
928 first_chars = false;
929 advance_conters(ch, &k, &width);
930 break;
934 else {
935 /* find first hard return */
936 next_line = find_first_feed(cur_line, size);
939 if (next_line == NULL)
940 if (size == search_len) {
941 if (prefs.word_mode == WRAP) /* Find last space */
942 next_line = find_last_space(cur_line, size);
944 if (next_line == NULL) {
945 next_line = crop_at_width(cur_line);
947 else {
948 if (prefs.word_mode == WRAP) {
949 for (i=0;i<WRAP_TRIM;i++) {
950 if (!(isspace(next_line[0]) && !BUFFER_OOB(next_line)))
951 break;
952 next_line++;
958 if (prefs.line_mode == EXPAND)
959 if (!BUFFER_OOB(next_line)) /* Not Null & not out of bounds */
960 if (next_line[0] == 0)
961 if (next_line != cur_line)
962 return (unsigned char*) next_line;
964 /* If next_line is pointing to a zero, increment it; i.e.,
965 leave the terminator at the end of cur_line. If pointing
966 to a hyphen, increment only if there is room to display
967 the hyphen on current line (won't apply in WIDE mode,
968 since it's guarenteed there won't be room). */
969 if (!BUFFER_OOB(next_line)) /* Not Null & not out of bounds */
970 if (next_line[0] == 0)/* ||
971 (next_line[0] == '-' && next_line-cur_line < draw_columns)) */
972 next_line++;
974 if (BUFFER_OOB(next_line))
976 if (BUFFER_EOF() && next_line != cur_line)
977 return (unsigned char*) next_line;
978 return NULL;
981 if (is_short)
982 *is_short = false;
984 return (unsigned char*) next_line;
987 static unsigned char* find_prev_line(const unsigned char* cur_line)
989 const unsigned char *prev_line = NULL;
990 const unsigned char *p;
992 if BUFFER_OOB(cur_line)
993 return NULL;
995 /* To wrap consistently at the same places, we must
996 start with a known hard return, then work downwards.
997 We can either search backwards for a hard return,
998 or simply start wrapping downwards from top of buffer.
999 If current line is not near top of buffer, this is
1000 a file with long lines (paragraphs). We would need to
1001 read earlier sectors before we could decide how to
1002 properly wrap the lines above the current line, but
1003 it probably is not worth the disk access. Instead,
1004 start with top of buffer and wrap down from there.
1005 This may result in some lines wrapping at different
1006 points from where they wrap when scrolling down.
1007 If buffer is at top of file, start at top of buffer. */
1009 if ((prefs.line_mode == JOIN) || (prefs.line_mode == REFLOW))
1010 prev_line = p = NULL;
1011 else
1012 prev_line = p = find_last_feed(buffer, cur_line-buffer-1);
1013 /* Null means no line feeds in buffer above current line. */
1015 if (prev_line == NULL)
1016 if (BUFFER_BOF() || cur_line - buffer > READ_PREV_ZONE)
1017 prev_line = p = buffer;
1018 /* (else return NULL and read previous block) */
1020 /* Wrap downwards until too far, then use the one before. */
1021 while (p != NULL && p < cur_line) {
1022 prev_line = p;
1023 p = find_next_line(prev_line, NULL);
1026 if (BUFFER_OOB(prev_line))
1027 return NULL;
1029 return (unsigned char*) prev_line;
1032 static void check_bom(void)
1034 unsigned char bom[BOM_SIZE];
1035 off_t orig = rb->lseek(fd, 0, SEEK_CUR);
1037 is_bom = false;
1039 rb->lseek(fd, 0, SEEK_SET);
1041 if (rb->read(fd, bom, BOM_SIZE) == BOM_SIZE)
1042 is_bom = !memcmp(bom, BOM, BOM_SIZE);
1044 rb->lseek(fd, orig, SEEK_SET);
1047 static void fill_buffer(long pos, unsigned char* buf, unsigned size)
1049 /* Read from file and preprocess the data */
1050 /* To minimize disk access, always read on sector boundaries */
1051 unsigned numread, i;
1052 bool found_CR = false;
1053 off_t offset = rb->lseek(fd, pos, SEEK_SET);
1055 if (offset == 0 && prefs.encoding == UTF_8 && is_bom)
1056 rb->lseek(fd, BOM_SIZE, SEEK_SET);
1058 numread = rb->read(fd, buf, size - 1);
1059 buf[numread] = 0;
1060 rb->button_clear_queue(); /* clear button queue */
1062 for(i = 0; i < numread; i++) {
1063 switch(buf[i]) {
1064 case '\r':
1065 if (mac_text) {
1066 buf[i] = 0;
1068 else {
1069 buf[i] = ' ';
1070 found_CR = true;
1072 break;
1074 case '\n':
1075 buf[i] = 0;
1076 found_CR = false;
1077 break;
1079 case 0: /* No break between case 0 and default, intentionally */
1080 buf[i] = ' ';
1081 default:
1082 if (found_CR) {
1083 buf[i - 1] = 0;
1084 found_CR = false;
1085 mac_text = true;
1087 break;
1092 static int viewer_find_bookmark(int page, int line)
1094 int i;
1096 for (i = 0; i < bookmark_count; i++)
1098 if (bookmarks[i].page == page && bookmarks[i].line == line)
1099 return i;
1101 return -1;
1104 static int read_and_synch(int direction)
1106 /* Read next (or prev) block, and reposition global pointers. */
1107 /* direction: 1 for down (i.e., further into file), -1 for up */
1108 int move_size, move_vector, offset;
1109 unsigned char *fill_buf;
1111 if (direction == -1) /* up */ {
1112 move_size = SMALL_BLOCK_SIZE;
1113 offset = 0;
1114 fill_buf = TOP_SECTOR;
1115 rb->memcpy(BOTTOM_SECTOR, MID_SECTOR, SMALL_BLOCK_SIZE);
1116 rb->memcpy(MID_SECTOR, TOP_SECTOR, SMALL_BLOCK_SIZE);
1118 else /* down */ {
1119 if (prefs.view_mode == WIDE) {
1120 /* WIDE mode needs more buffer so we have to read smaller blocks */
1121 move_size = SMALL_BLOCK_SIZE;
1122 offset = LARGE_BLOCK_SIZE;
1123 fill_buf = BOTTOM_SECTOR;
1124 rb->memcpy(TOP_SECTOR, MID_SECTOR, SMALL_BLOCK_SIZE);
1125 rb->memcpy(MID_SECTOR, BOTTOM_SECTOR, SMALL_BLOCK_SIZE);
1127 else {
1128 move_size = LARGE_BLOCK_SIZE;
1129 offset = SMALL_BLOCK_SIZE;
1130 fill_buf = MID_SECTOR;
1131 rb->memcpy(TOP_SECTOR, BOTTOM_SECTOR, SMALL_BLOCK_SIZE);
1134 move_vector = direction * move_size;
1135 screen_top_ptr -= move_vector;
1136 file_pos += move_vector;
1137 buffer_end = BUFFER_END(); /* Update whenever file_pos changes */
1138 fill_buffer(file_pos + offset, fill_buf, move_size);
1139 return move_vector;
1142 static void get_next_line_position(unsigned char **line_begin,
1143 unsigned char **line_end,
1144 bool *is_short)
1146 int resynch_move;
1148 *line_begin = *line_end;
1149 *line_end = find_next_line(*line_begin, is_short);
1151 if (*line_end == NULL && !BUFFER_EOF())
1153 resynch_move = read_and_synch(1); /* Read block & move ptrs */
1154 *line_begin -= resynch_move;
1155 if (next_line_ptr > buffer)
1156 next_line_ptr -= resynch_move;
1158 *line_end = find_next_line(*line_begin, is_short);
1162 static void increment_current_line(void)
1164 if (cline < display_lines)
1165 cline++;
1166 else if (cpage < MAX_PAGE)
1168 cpage++;
1169 cline = 1;
1173 static void decrement_current_line(void)
1175 if (cline > 1)
1176 cline--;
1177 else if (cpage > 1)
1179 cpage--;
1180 cline = display_lines;
1184 static void viewer_scroll_up(void)
1186 unsigned char *p;
1188 p = find_prev_line(screen_top_ptr);
1189 if (p == NULL && !BUFFER_BOF()) {
1190 read_and_synch(-1);
1191 p = find_prev_line(screen_top_ptr);
1193 if (p != NULL)
1194 screen_top_ptr = p;
1196 decrement_current_line();
1199 static void viewer_scroll_down(bool autoscroll)
1201 if (cpage == lpage)
1202 return;
1204 if (next_line_ptr != NULL)
1205 screen_top_ptr = next_line_ptr;
1207 if (prefs.scroll_mode == LINE || autoscroll)
1208 increment_current_line();
1211 static void viewer_scroll_to_top_line(void)
1213 int line;
1215 for (line = cline; line > 1; line--)
1216 viewer_scroll_up();
1219 #ifdef HAVE_LCD_BITMAP
1220 static void viewer_scrollbar(void) {
1221 int items, min_shown, max_shown, sb_begin_y, sb_height;
1223 items = (int) file_size; /* (SH1 int is same as long) */
1224 min_shown = (int) file_pos + (screen_top_ptr - buffer);
1226 if (next_screen_ptr == NULL)
1227 max_shown = items;
1228 else
1229 max_shown = min_shown + (next_screen_ptr - screen_top_ptr);
1231 sb_begin_y = header_height;
1232 sb_height = LCD_HEIGHT - header_height - footer_height;
1234 rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN],0, sb_begin_y,
1235 SCROLLBAR_WIDTH-1, sb_height,
1236 items, min_shown, max_shown, VERTICAL);
1238 #endif
1240 #ifdef HAVE_LCD_BITMAP
1241 static void viewer_show_header(void)
1243 if (prefs.header_mode == HD_SBAR || prefs.header_mode == HD_BOTH)
1244 rb->gui_syncstatusbar_draw(rb->statusbars, true);
1246 if (prefs.header_mode == HD_PATH || prefs.header_mode == HD_BOTH)
1247 rb->lcd_putsxy(0, header_height - pf->height, file_name);
1250 static void viewer_show_footer(void)
1252 if (prefs.footer_mode == FT_SBAR || prefs.footer_mode == FT_BOTH)
1253 rb->gui_syncstatusbar_draw(rb->statusbars, true);
1255 if (prefs.footer_mode == FT_PAGE || prefs.footer_mode == FT_BOTH)
1257 unsigned char buf[12];
1259 if (cline == 1)
1260 rb->snprintf(buf, sizeof(buf), "%d", cpage);
1261 else
1262 rb->snprintf(buf, sizeof(buf), "%d - %d", cpage, cpage+1);
1264 rb->lcd_putsxy(0, LCD_HEIGHT - footer_height, buf);
1267 #endif
1269 /* We draw a diacritic char over a non-diacritic one. Therefore, such chars are
1270 * not considered to occupy space, therefore buffers might have more than
1271 * max_columns characters. The DIACRITIC_FACTOR is the max ratio between all
1272 * characters and non-diacritic characters in the buffer
1274 #define DIACRITIC_FACTOR 2
1276 static void viewer_draw(int col)
1278 int i, j, k, line_len, line_width, spaces, left_col=0;
1279 int width, extra_spaces, indent_spaces, spaces_per_word, spaces_width;
1280 bool multiple_spacing, line_is_short;
1281 unsigned short ch;
1282 unsigned char *str, *oldstr;
1283 unsigned char *line_begin;
1284 unsigned char *line_end;
1285 unsigned char c;
1286 int max_chars = max_columns * DIACRITIC_FACTOR;
1287 unsigned char scratch_buffer[max_chars + 1];
1288 unsigned char utf8_buffer[max_chars * 4 + 1];
1289 unsigned char *endptr;
1291 /* If col==-1 do all calculations but don't display */
1292 if (col != -1) {
1293 #ifdef HAVE_LCD_BITMAP
1294 left_col = prefs.need_scrollbar? SCROLLBAR_WIDTH:0;
1295 #else
1296 left_col = 0;
1297 #endif
1298 rb->lcd_clear_display();
1300 max_line_len = 0;
1301 line_begin = line_end = screen_top_ptr;
1303 for (i = 0; i < display_lines; i++) {
1304 if (BUFFER_OOB(line_end))
1306 if (lpage == cpage)
1307 break; /* Happens after display last line at BUFFER_EOF() */
1309 if (lpage == 0 && cline == 1)
1311 lpage = cpage;
1312 last_screen_top_ptr = screen_top_ptr;
1313 last_file_pos = file_pos;
1317 get_next_line_position(&line_begin, &line_end, &line_is_short);
1318 if (line_end == NULL)
1320 if (BUFFER_OOB(line_begin))
1321 break;
1322 line_end = buffer_end + 1;
1325 line_len = line_end - line_begin;
1327 /* calculate line_len */
1328 str = oldstr = line_begin;
1329 j = -1;
1330 while (str < line_end) {
1331 oldstr = str;
1332 str = crop_at_width(str);
1333 j++;
1334 if (oldstr == str)
1336 oldstr = line_end;
1337 break;
1340 /* width of un-displayed part of the line */
1341 line_width = j*draw_columns;
1342 spaces_width = 0;
1343 while (oldstr < line_end) {
1344 oldstr = get_ucs(oldstr, &ch);
1345 /* add width of displayed part of the line */
1346 if (ch)
1348 int dw = glyph_width(ch);
1350 /* avoid counting spaces at the end of the line */
1351 if (ch == ' ')
1353 spaces_width += dw;
1355 else
1357 line_width += dw + spaces_width;
1358 spaces_width = 0;
1363 if (prefs.line_mode == JOIN) {
1364 if (line_begin[0] == 0) {
1365 line_begin++;
1366 if (prefs.word_mode == CHOP)
1367 line_end++;
1368 else
1369 line_len--;
1371 for (j=k=spaces=0; j < line_len; j++) {
1372 if (k == max_chars)
1373 break;
1375 c = line_begin[j];
1376 switch (c) {
1377 case ' ':
1378 spaces++;
1379 break;
1380 case 0:
1381 spaces = 0;
1382 scratch_buffer[k++] = ' ';
1383 break;
1384 default:
1385 while (spaces) {
1386 spaces--;
1387 scratch_buffer[k++] = ' ';
1388 if (k == max_chars - 1)
1389 break;
1391 scratch_buffer[k++] = c;
1392 break;
1395 if (col != -1) {
1396 scratch_buffer[k] = 0;
1397 endptr = decode2utf8(scratch_buffer, utf8_buffer, col, draw_columns);
1398 *endptr = 0;
1401 else if (prefs.line_mode == REFLOW) {
1402 if (line_begin[0] == 0) {
1403 line_begin++;
1404 if (prefs.word_mode == CHOP)
1405 line_end++;
1406 else
1407 line_len--;
1410 indent_spaces = 0;
1411 if (!line_is_short) {
1412 multiple_spacing = false;
1413 width=spaces=0;
1414 for (str = line_begin; str < line_end; ) {
1415 str = get_ucs(str, &ch);
1416 switch (ch) {
1417 case ' ':
1418 case 0:
1419 if ((str == line_begin) && (prefs.word_mode==WRAP))
1420 /* special case: indent the paragraph,
1421 * don't count spaces */
1422 indent_spaces = par_indent_spaces;
1423 else if (!multiple_spacing)
1424 spaces++;
1425 multiple_spacing = true;
1426 break;
1427 default:
1428 multiple_spacing = false;
1429 width += glyph_width(ch);
1430 break;
1433 if (multiple_spacing) spaces--;
1435 if (spaces) {
1436 /* total number of spaces to insert between words */
1437 extra_spaces = (max_width-width)/glyph_width(' ')
1438 - indent_spaces;
1439 /* number of spaces between each word*/
1440 spaces_per_word = extra_spaces / spaces;
1441 /* number of words with n+1 spaces (to fill up) */
1442 extra_spaces = extra_spaces % spaces;
1443 if (spaces_per_word > 2) { /* too much spacing is awful */
1444 spaces_per_word = 3;
1445 extra_spaces = 0;
1447 } else { /* this doesn't matter much... no spaces anyway */
1448 spaces_per_word = extra_spaces = 0;
1450 } else { /* end of a paragraph: don't fill line */
1451 spaces_per_word = 1;
1452 extra_spaces = 0;
1455 multiple_spacing = false;
1456 for (j=k=spaces=0; j < line_len; j++) {
1457 if (k == max_chars)
1458 break;
1460 c = line_begin[j];
1461 switch (c) {
1462 case ' ':
1463 case 0:
1464 if (j==0 && prefs.word_mode==WRAP) { /* indent paragraph */
1465 for (j=0; j<par_indent_spaces; j++)
1466 scratch_buffer[k++] = ' ';
1467 j=0;
1469 else if (!multiple_spacing) {
1470 for (width = spaces<extra_spaces ? -1:0; width < spaces_per_word; width++)
1471 scratch_buffer[k++] = ' ';
1472 spaces++;
1474 multiple_spacing = true;
1475 break;
1476 default:
1477 scratch_buffer[k++] = c;
1478 multiple_spacing = false;
1479 break;
1482 if (col != -1) {
1483 scratch_buffer[k] = 0;
1484 endptr = decode2utf8(scratch_buffer, utf8_buffer, col, draw_columns);
1485 *endptr = 0;
1488 else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */
1489 if ((col != -1) && (line_width > col)) {
1490 str = oldstr = line_begin;
1491 k = col;
1492 width = 0;
1493 while( (width<draw_columns) && (oldstr<line_end) )
1495 oldstr = get_ucs(oldstr, &ch);
1496 if (k > 0) {
1497 k -= glyph_width(ch);
1498 line_begin = oldstr;
1499 } else {
1500 width += glyph_width(ch);
1504 if(prefs.view_mode==WIDE)
1505 endptr = rb->iso_decode(line_begin, utf8_buffer,
1506 prefs.encoding, oldstr-line_begin);
1507 else
1508 endptr = rb->iso_decode(line_begin, utf8_buffer,
1509 prefs.encoding, line_end-line_begin);
1510 *endptr = 0;
1514 /* display on screen the displayed part of the line */
1515 if (col != -1 && line_width > col)
1517 int dpage = (cline+i <= display_lines)?cpage:cpage+1;
1518 int dline = cline+i - ((cline+i <= display_lines)?0:display_lines);
1519 bool bflag = (viewer_find_bookmark(dpage, dline) >= 0);
1520 #ifdef HAVE_LCD_BITMAP
1521 int dy = i * pf->height + header_height;
1522 int dx = (prefs.alignment == LEFT) ? left_col : LCD_WIDTH - line_width;
1523 #endif
1524 if (bflag)
1525 #ifdef HAVE_LCD_BITMAP
1527 rb->lcd_set_drawmode(DRMODE_BG|DRMODE_FG);
1528 rb->lcd_fillrect(left_col, dy, LCD_WIDTH - left_col, pf->height);
1529 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1531 rb->lcd_putsxy(dx, dy, utf8_buffer);
1532 rb->lcd_set_drawmode(DRMODE_SOLID);
1533 #else
1535 rb->lcd_puts(left_col, i, BOOKMARK_ICON);
1537 rb->lcd_puts(left_col+1, i, utf8_buffer);
1538 #endif
1540 if (line_width > max_line_len)
1541 max_line_len = line_width;
1543 if (i == 0)
1544 next_line_ptr = line_end;
1546 next_screen_ptr = line_end;
1547 if (BUFFER_OOB(next_screen_ptr))
1548 next_screen_ptr = NULL;
1550 #ifdef HAVE_LCD_BITMAP
1551 next_screen_to_draw_ptr = prefs.page_mode==OVERLAP? line_begin: next_screen_ptr;
1553 if (prefs.need_scrollbar)
1554 viewer_scrollbar();
1555 #else
1556 next_screen_to_draw_ptr = next_screen_ptr;
1557 #endif
1559 #ifdef HAVE_LCD_BITMAP
1560 /* show header */
1561 viewer_show_header();
1563 /* show footer */
1564 viewer_show_footer();
1565 #endif
1567 if (col != -1)
1568 rb->lcd_update();
1571 static void viewer_top(void)
1573 /* Read top of file into buffer
1574 and point screen pointer to top */
1575 if (file_pos != 0)
1577 rb->splash(0, "Loading...");
1579 file_pos = 0;
1580 buffer_end = BUFFER_END(); /* Update whenever file_pos changes */
1581 fill_buffer(0, buffer, buffer_size);
1584 screen_top_ptr = buffer;
1585 cpage = 1;
1586 cline = 1;
1589 static void viewer_bottom(void)
1591 unsigned char *line_begin;
1592 unsigned char *line_end;
1594 rb->splash(0, "Loading...");
1596 if (last_screen_top_ptr)
1598 cpage = lpage;
1599 cline = 1;
1600 screen_top_ptr = last_screen_top_ptr;
1601 file_pos = last_file_pos;
1602 fill_buffer(file_pos, buffer, buffer_size);
1603 buffer_end = BUFFER_END();
1604 return;
1607 line_end = screen_top_ptr;
1609 while (!BUFFER_EOF() || !BUFFER_OOB(line_end))
1611 get_next_line_position(&line_begin, &line_end, NULL);
1612 if (line_end == NULL)
1613 break;
1615 increment_current_line();
1616 if (cline == 1)
1617 screen_top_ptr = line_end;
1619 lpage = cpage;
1620 cline = 1;
1621 last_screen_top_ptr = screen_top_ptr;
1622 last_file_pos = file_pos;
1623 buffer_end = BUFFER_END();
1626 #ifdef HAVE_LCD_BITMAP
1627 static void init_need_scrollbar(void) {
1628 /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
1629 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
1630 viewer_draw(-1);
1631 prefs.need_scrollbar = NEED_SCROLLBAR();
1632 draw_columns = prefs.need_scrollbar? display_columns-SCROLLBAR_WIDTH : display_columns;
1633 par_indent_spaces = draw_columns/(5*glyph_width(' '));
1634 calc_max_width();
1637 static void init_header_and_footer(void)
1639 header_height = 0;
1640 footer_height = 0;
1641 if (rb->global_settings->statusbar == STATUSBAR_TOP)
1643 if (prefs.header_mode == HD_SBAR || prefs.header_mode == HD_BOTH)
1644 header_height = STATUSBAR_HEIGHT;
1646 if (prefs.footer_mode == FT_SBAR)
1647 prefs.footer_mode = FT_NONE;
1648 else if (prefs.footer_mode == FT_BOTH)
1649 prefs.footer_mode = FT_PAGE;
1651 else if (rb->global_settings->statusbar == STATUSBAR_BOTTOM)
1653 if (prefs.footer_mode == FT_SBAR || prefs.footer_mode == FT_BOTH)
1654 footer_height = STATUSBAR_HEIGHT;
1656 if (prefs.header_mode == HD_SBAR)
1657 prefs.header_mode = HD_NONE;
1658 else if (prefs.header_mode == HD_BOTH)
1659 prefs.header_mode = HD_PATH;
1661 else /* STATUSBAR_OFF || STATUSBAR_CUSTOM */
1663 if (prefs.header_mode == HD_SBAR)
1664 prefs.header_mode = HD_NONE;
1665 else if (prefs.header_mode == HD_BOTH)
1666 prefs.header_mode = HD_PATH;
1668 if (prefs.footer_mode == FT_SBAR)
1669 prefs.footer_mode = FT_NONE;
1670 else if (prefs.footer_mode == FT_BOTH)
1671 prefs.footer_mode = FT_PAGE;
1674 if (prefs.header_mode == HD_NONE || prefs.header_mode == HD_PATH ||
1675 prefs.footer_mode == FT_NONE || prefs.footer_mode == FT_PAGE)
1676 rb->gui_syncstatusbar_draw(rb->statusbars, false);
1678 if (prefs.header_mode == HD_PATH || prefs.header_mode == HD_BOTH)
1679 header_height += pf->height;
1680 if (prefs.footer_mode == FT_PAGE || prefs.footer_mode == FT_BOTH)
1681 footer_height += pf->height;
1683 display_lines = (LCD_HEIGHT - header_height - footer_height) / pf->height;
1685 lpage = 0;
1686 last_file_pos = 0;
1687 last_screen_top_ptr = NULL;
1690 static bool change_font(unsigned char *font)
1692 unsigned char buf[MAX_PATH];
1694 if (font == NULL || *font == '\0')
1695 return false;
1697 rb->snprintf(buf, MAX_PATH, "%s/%s.fnt", FONT_DIR, font);
1698 if (rb->font_load(NULL, buf) < 0) {
1699 rb->splash(HZ/2, "Font load failed.");
1700 return false;
1703 return true;
1705 #endif
1707 static bool viewer_init(void)
1709 #ifdef HAVE_LCD_BITMAP
1710 /* initialize fonts */
1711 pf = rb->font_get(FONT_UI);
1712 if (pf == NULL)
1713 return false;
1715 draw_columns = display_columns = LCD_WIDTH;
1716 #else
1717 /* REAL fixed pitch :) all chars use up 1 cell */
1718 display_lines = 2;
1719 draw_columns = display_columns = 11;
1720 par_indent_spaces = 2;
1721 #endif
1723 fd = rb->open(file_name, O_RDONLY);
1724 if (fd < 0)
1725 return false;
1727 /* Init mac_text value used in processing buffer */
1728 mac_text = false;
1730 return true;
1733 /* When a file is UTF-8 file with BOM, if prefs.encoding is UTF-8,
1734 * then file size decreases only BOM_SIZE.
1736 static void get_filesize(void)
1738 file_size = rb->filesize(fd);
1739 if (file_size == -1)
1740 return;
1742 if (prefs.encoding == UTF_8 && is_bom)
1743 file_size -= BOM_SIZE;
1746 static int bm_comp(const void *a, const void *b)
1748 struct bookmark_info *pa;
1749 struct bookmark_info *pb;
1751 pa = (struct bookmark_info*)a;
1752 pb = (struct bookmark_info*)b;
1754 if (pa->page != pb->page)
1755 return pa->page - pb->page;
1757 return pa->line - pb->line;
1760 static void viewer_add_bookmark(void)
1762 if (bookmark_count >= MAX_BOOKMARKS-1)
1763 return;
1765 bookmarks[bookmark_count].file_position
1766 = file_pos + screen_top_ptr - buffer;
1767 bookmarks[bookmark_count].page = cpage;
1768 bookmarks[bookmark_count].line = cline;
1769 bookmarks[bookmark_count].flag = BOOKMARK_USER;
1770 bookmark_count++;
1773 static int viewer_add_last_read_bookmark(void)
1775 int i;
1777 i = viewer_find_bookmark(cpage, cline);
1778 if (i >= 0)
1779 bookmarks[i].flag |= BOOKMARK_LAST;
1780 else
1782 viewer_add_bookmark();
1783 i = bookmark_count-1;
1784 bookmarks[i].flag = BOOKMARK_LAST;
1786 return i;
1789 static void viewer_remove_bookmark(int i)
1791 int j;
1793 if (i < 0 || i >= bookmark_count)
1794 return;
1796 for (j = i+1; j < bookmark_count; j++)
1797 rb->memcpy(&bookmarks[j-1], &bookmarks[j],
1798 sizeof(struct bookmark_info));
1800 bookmark_count--;
1803 static void viewer_remove_last_read_bookmark(void)
1805 int i, j;
1807 for (i = 0; i < bookmark_count; i++)
1809 if (bookmarks[i].flag & BOOKMARK_LAST)
1811 if (bookmarks[i].flag == BOOKMARK_LAST)
1813 for (j = i+1; j < bookmark_count; j++)
1814 rb->memcpy(&bookmarks[j-1], &bookmarks[j],
1815 sizeof(struct bookmark_info));
1817 bookmark_count--;
1819 else
1820 bookmarks[i].flag = BOOKMARK_USER;
1821 break;
1826 static int viewer_get_last_read_bookmark(void)
1828 int i;
1830 for (i = 0; i < bookmark_count; i++)
1832 if (bookmarks[i].flag & BOOKMARK_LAST)
1833 return i;
1835 return -1;
1838 static void viewer_select_bookmark(int initval)
1840 int i;
1841 int ipage = 0;
1842 int iline = 0;
1843 int screen_pos;
1844 int screen_top;
1845 int selected = -1;
1847 struct opt_items items[bookmark_count];
1848 unsigned char names[bookmark_count][38];
1850 if (initval >= 0 && initval < bookmark_count)
1852 ipage = bookmarks[initval].page;
1853 iline = bookmarks[initval].line;
1856 rb->qsort(bookmarks, bookmark_count, sizeof(struct bookmark_info),
1857 bm_comp);
1859 for (i = 0; i < bookmark_count; i++)
1861 rb->snprintf(names[i], sizeof(names[0]),
1862 #if CONFIG_KEYPAD != PLAYER_PAD
1863 "%sPage: %d Line: %d",
1864 #else
1865 "%sP:%d L:%d",
1866 #endif
1867 (bookmarks[i].flag&BOOKMARK_LAST)? "*":" ",
1868 bookmarks[i].page,
1869 bookmarks[i].line);
1870 items[i].string = names[i];
1871 items[i].voice_id = -1;
1872 if (selected < 0 && bookmarks[i].page == ipage && bookmarks[i].line == iline)
1873 selected = i;
1876 rb->set_option("Select bookmark", &selected, INT, items,
1877 sizeof(items) / sizeof(items[0]), NULL);
1879 if (selected < 0 || selected >= bookmark_count)
1881 if (initval < 0 || (selected = viewer_get_last_read_bookmark()) < 0)
1883 if (initval < 0)
1884 rb->splash(HZ, "Start the first page.");
1885 file_pos = 0;
1886 screen_top_ptr = buffer;
1887 cpage = 1;
1888 cline = 1;
1889 buffer_end = BUFFER_END();
1890 return;
1894 screen_pos = bookmarks[selected].file_position;
1895 screen_top = screen_pos % buffer_size;
1896 file_pos = screen_pos - screen_top;
1897 screen_top_ptr = buffer + screen_top;
1898 cpage = bookmarks[selected].page;
1899 cline = bookmarks[selected].line;
1900 buffer_end = BUFFER_END();
1903 static void viewer_default_preferences(void)
1905 prefs.word_mode = WRAP;
1906 prefs.line_mode = NORMAL;
1907 prefs.view_mode = NARROW;
1908 prefs.alignment = LEFT;
1909 prefs.scroll_mode = PAGE;
1910 prefs.page_mode = NO_OVERLAP;
1911 prefs.scrollbar_mode = SB_OFF;
1912 rb->memset(prefs.font, 0, MAX_PATH);
1913 #ifdef HAVE_LCD_BITMAP
1914 prefs.header_mode = HD_BOTH;
1915 prefs.footer_mode = FT_BOTH;
1916 rb->snprintf(prefs.font, MAX_PATH, "%s", rb->global_settings->font_file);
1917 #else
1918 prefs.header_mode = HD_NONE;
1919 prefs.footer_mode = FT_NONE;
1920 #endif
1921 prefs.autoscroll_speed = 1;
1922 /* Set codepage to system default */
1923 prefs.encoding = rb->global_settings->default_codepage;
1926 static bool viewer_read_preferences(int pfd, int version)
1928 unsigned char buf[PREFERENCES_SIZE];
1929 unsigned char *p = buf;
1931 if (rb->read(pfd, buf, sizeof(buf)) != sizeof(buf))
1932 return false;
1934 prefs.word_mode = *p++;
1935 prefs.line_mode = *p++;
1936 prefs.view_mode = *p++;
1937 if (version > 0)
1938 prefs.alignment = *p++;
1939 else
1940 prefs.alignment = LEFT;
1941 prefs.encoding = *p++;
1942 prefs.scrollbar_mode = *p++;
1943 prefs.need_scrollbar = *p++;
1944 prefs.page_mode = *p++;
1945 prefs.header_mode = *p++;
1946 prefs.footer_mode = *p++;
1947 prefs.scroll_mode = *p++;
1948 prefs.autoscroll_speed = *p++;
1949 rb->memcpy(prefs.font, p, MAX_PATH);
1950 return true;
1953 static bool viewer_write_preferences(int pfd)
1955 unsigned char buf[PREFERENCES_SIZE];
1956 unsigned char *p = buf;
1958 *p++ = prefs.word_mode;
1959 *p++ = prefs.line_mode;
1960 *p++ = prefs.view_mode;
1961 *p++ = prefs.alignment;
1962 *p++ = prefs.encoding;
1963 *p++ = prefs.scrollbar_mode;
1964 *p++ = prefs.need_scrollbar;
1965 *p++ = prefs.page_mode;
1966 *p++ = prefs.header_mode;
1967 *p++ = prefs.footer_mode;
1968 *p++ = prefs.scroll_mode;
1969 *p++ = prefs.autoscroll_speed;
1970 rb->memcpy(p, prefs.font, MAX_PATH);
1972 return (rb->write(pfd, buf, sizeof(buf)) == sizeof(buf));
1975 static bool viewer_read_bookmark_info(int bfd, struct bookmark_info *b)
1977 unsigned char buf[BOOKMARK_SIZE];
1979 if (rb->read(bfd, buf, sizeof(buf)) != sizeof(buf))
1980 return false;
1982 b->file_position = (buf[0] << 24)|(buf[1] << 16)|(buf[2] << 8)|buf[3];
1983 b->page = (buf[4] << 8)|buf[5];
1984 b->line = buf[6];
1985 b->flag = buf[7];
1987 return true;
1990 static bool viewer_read_bookmark_infos(int bfd)
1992 unsigned char c;
1993 int i;
1995 if (rb->read(bfd, &c, 1) != 1)
1997 bookmark_count = 0;
1998 return false;
2001 bookmark_count = c;
2002 if (bookmark_count > MAX_BOOKMARKS)
2003 bookmark_count = MAX_BOOKMARKS;
2005 for (i = 0; i < bookmark_count; i++)
2007 if (!viewer_read_bookmark_info(bfd, &bookmarks[i]))
2009 bookmark_count = i;
2010 return false;
2013 return true;
2016 static bool viewer_write_bookmark_info(int bfd, struct bookmark_info *b)
2018 unsigned char buf[BOOKMARK_SIZE];
2019 unsigned char *p = buf;
2020 unsigned long ul;
2022 ul = b->file_position;
2023 *p++ = ul >> 24;
2024 *p++ = ul >> 16;
2025 *p++ = ul >> 8;
2026 *p++ = ul;
2028 ul = b->page;
2029 *p++ = ul >> 8;
2030 *p++ = ul;
2032 *p++ = b->line;
2033 *p = b->flag;
2035 return (rb->write(bfd, buf, sizeof(buf)) == sizeof(buf));
2038 static bool viewer_write_bookmark_infos(int bfd)
2040 unsigned char c = bookmark_count;
2041 int i;
2043 if (rb->write(bfd, &c, 1) != 1)
2044 return false;
2046 for (i = 0; i < bookmark_count; i++)
2048 if (!viewer_write_bookmark_info(bfd, &bookmarks[i]))
2049 return false;
2052 return true;
2055 static bool viewer_load_global_settings(void)
2057 unsigned buf[GLOBAL_SETTINGS_H_SIZE];
2058 int sfd = rb->open(GLOBAL_SETTINGS_FILE, O_RDONLY);
2059 int version;
2060 bool res = false;
2062 if (sfd < 0)
2063 return false;
2065 if ((rb->read(sfd, buf, GLOBAL_SETTINGS_H_SIZE) == GLOBAL_SETTINGS_H_SIZE) ||
2066 (rb->memcmp(buf, GLOBAL_SETTINGS_HEADER, GLOBAL_SETTINGS_H_SIZE - 1) == 0))
2068 version = buf[GLOBAL_SETTINGS_H_SIZE - 1] - GLOBAL_SETTINGS_FIRST_VERSION;
2069 res = viewer_read_preferences(sfd, version);
2071 rb->close(sfd);
2072 return res;
2075 static bool viewer_save_global_settings(void)
2077 int sfd = rb->open(GLOBAL_SETTINGS_TMP_FILE, O_WRONLY|O_CREAT|O_TRUNC);
2079 if (sfd < 0)
2080 return false;
2082 if (rb->write(sfd, &GLOBAL_SETTINGS_HEADER, GLOBAL_SETTINGS_H_SIZE)
2083 != GLOBAL_SETTINGS_H_SIZE ||
2084 !viewer_write_preferences(sfd))
2086 rb->close(sfd);
2087 rb->remove(GLOBAL_SETTINGS_TMP_FILE);
2088 return false;
2090 rb->close(sfd);
2091 rb->remove(GLOBAL_SETTINGS_FILE);
2092 rb->rename(GLOBAL_SETTINGS_TMP_FILE, GLOBAL_SETTINGS_FILE);
2093 return true;
2096 static bool viewer_load_settings(void)
2098 unsigned char buf[MAX_PATH+2];
2099 unsigned int fcount;
2100 unsigned int i;
2101 bool res = false;
2102 int sfd;
2103 unsigned int size;
2104 int version;
2106 sfd = rb->open(SETTINGS_FILE, O_RDONLY);
2107 if (sfd < 0)
2108 goto read_end;
2110 if ((rb->read(sfd, buf, SETTINGS_H_SIZE+2) != SETTINGS_H_SIZE+2) ||
2111 rb->memcmp(buf, SETTINGS_HEADER, SETTINGS_H_SIZE - 1))
2113 /* illegal setting file */
2114 rb->close(sfd);
2116 if (rb->file_exists(SETTINGS_FILE))
2117 rb->remove(SETTINGS_FILE);
2119 goto read_end;
2122 version = buf[SETTINGS_H_SIZE - 1] - SETTINGS_FIRST_VERSION;
2123 fcount = (buf[SETTINGS_H_SIZE] << 8) | buf[SETTINGS_H_SIZE+1];
2124 for (i = 0; i < fcount; i++)
2126 if (rb->read(sfd, buf, MAX_PATH+2) != MAX_PATH+2)
2127 break;
2129 size = (buf[MAX_PATH] << 8) | buf[MAX_PATH+1];
2130 if (rb->strcmp(buf, file_name))
2132 if (rb->lseek(sfd, size, SEEK_CUR) < 0)
2133 break;
2134 continue;
2136 if (!viewer_read_preferences(sfd, version))
2137 break;
2139 res = viewer_read_bookmark_infos(sfd);
2140 break;
2143 rb->close(sfd);
2145 read_end:
2146 if (!res)
2148 /* load global settings */
2149 if (!viewer_load_global_settings())
2150 viewer_default_preferences();
2152 file_pos = 0;
2153 screen_top_ptr = buffer;
2154 cpage = 1;
2155 cline = 1;
2156 bookmark_count = 0;
2159 rb->memcpy(&old_prefs, &prefs, sizeof(struct preferences));
2160 calc_max_width();
2162 if (bookmark_count > 1)
2163 viewer_select_bookmark(-1);
2164 else if (bookmark_count == 1)
2166 int screen_pos;
2167 int screen_top;
2169 screen_pos = bookmarks[0].file_position;
2170 screen_top = screen_pos % buffer_size;
2171 file_pos = screen_pos - screen_top;
2172 screen_top_ptr = buffer + screen_top;
2173 cpage = bookmarks[0].page;
2174 cline = bookmarks[0].line;
2177 viewer_remove_last_read_bookmark();
2179 check_bom();
2180 get_filesize();
2182 buffer_end = BUFFER_END(); /* Update whenever file_pos changes */
2184 if (BUFFER_OOB(screen_top_ptr))
2185 screen_top_ptr = buffer;
2187 fill_buffer(file_pos, buffer, buffer_size);
2188 if (prefs.scroll_mode == PAGE && cline > 1)
2189 viewer_scroll_to_top_line();
2191 /* remember the current position */
2192 start_position = file_pos + screen_top_ptr - buffer;
2194 #ifdef HAVE_LCD_BITMAP
2195 /* load prefs font if it is different than the global settings font */
2196 if (rb->strcmp(prefs.font, rb->global_settings->font_file)) {
2197 if (!change_font(prefs.font)) {
2198 /* fallback by resetting prefs font to the global settings font */
2199 rb->memset(prefs.font, 0, MAX_PATH);
2200 rb->snprintf(prefs.font, MAX_PATH, "%s",
2201 rb->global_settings->font_file);
2203 if (!change_font(prefs.font))
2204 return false;
2208 init_need_scrollbar();
2209 init_header_and_footer();
2210 #endif
2212 return true;
2215 static bool copy_bookmark_file(int sfd, int dfd, off_t start, off_t size)
2217 off_t rsize;
2219 if (rb->lseek(sfd, start, SEEK_SET) < 0)
2220 return false;
2222 while (size > 0)
2224 if (size > buffer_size)
2225 rsize = buffer_size;
2226 else
2227 rsize = size;
2228 size -= rsize;
2230 if (rb->read(sfd, buffer, rsize) != rsize ||
2231 rb->write(dfd, buffer, rsize) != rsize)
2232 return false;
2234 return true;
2237 static bool viewer_save_settings(void)
2239 unsigned char buf[MAX_PATH+2];
2240 unsigned int fcount = 0;
2241 unsigned int i;
2242 int idx;
2243 int ofd;
2244 int tfd;
2245 off_t first_copy_size = 0;
2246 off_t second_copy_start_pos = 0;
2247 off_t size;
2249 /* add reading page to bookmarks */
2250 idx = viewer_find_bookmark(cpage, cline);
2251 if (idx >= 0)
2252 bookmarks[idx].flag |= BOOKMARK_LAST;
2253 else
2255 viewer_add_bookmark();
2256 bookmarks[bookmark_count-1].flag = BOOKMARK_LAST;
2259 tfd = rb->open(SETTINGS_TMP_FILE, O_WRONLY|O_CREAT|O_TRUNC);
2260 if (tfd < 0)
2261 return false;
2263 ofd = rb->open(SETTINGS_FILE, O_RDWR);
2264 if (ofd >= 0)
2266 if ((rb->read(ofd, buf, SETTINGS_H_SIZE+2) != SETTINGS_H_SIZE+2) ||
2267 rb->memcmp(buf, SETTINGS_HEADER, SETTINGS_H_SIZE))
2269 rb->close(ofd);
2270 goto save_err;
2272 fcount = (buf[SETTINGS_H_SIZE] << 8) | buf[SETTINGS_H_SIZE+1];
2274 for (i = 0; i < fcount; i++)
2276 if (rb->read(ofd, buf, MAX_PATH+2) != MAX_PATH+2)
2278 rb->close(ofd);
2279 goto save_err;
2281 size = (buf[MAX_PATH] << 8) | buf[MAX_PATH+1];
2282 if (rb->strcmp(buf, file_name))
2284 if (rb->lseek(ofd, size, SEEK_CUR) < 0)
2286 rb->close(ofd);
2287 goto save_err;
2290 else
2292 first_copy_size = rb->lseek(ofd, 0, SEEK_CUR);
2293 if (first_copy_size < 0)
2295 rb->close(ofd);
2296 goto save_err;
2298 second_copy_start_pos = first_copy_size + size;
2299 first_copy_size -= MAX_PATH+2;
2300 fcount--;
2301 break;
2304 if (first_copy_size == 0)
2305 first_copy_size = rb->filesize(ofd);
2307 if (!copy_bookmark_file(ofd, tfd, 0, first_copy_size))
2309 rb->close(ofd);
2310 goto save_err;
2312 if (second_copy_start_pos > 0)
2314 if (!copy_bookmark_file(ofd, tfd, second_copy_start_pos,
2315 rb->filesize(ofd) - second_copy_start_pos))
2317 rb->close(ofd);
2318 goto save_err;
2321 rb->close(ofd);
2323 else
2325 rb->memcpy(buf, SETTINGS_HEADER, SETTINGS_H_SIZE);
2326 buf[SETTINGS_H_SIZE] = 0;
2327 buf[SETTINGS_H_SIZE+1] = 0;
2328 if (rb->write(tfd, buf, SETTINGS_H_SIZE+2) != SETTINGS_H_SIZE+2)
2329 goto save_err;
2332 /* copy to current read file's bookmarks */
2333 rb->memset(buf, 0, MAX_PATH);
2334 rb->snprintf(buf, MAX_PATH, "%s", file_name);
2336 size = PREFERENCES_SIZE + bookmark_count * BOOKMARK_SIZE + 1;
2337 buf[MAX_PATH] = size >> 8;
2338 buf[MAX_PATH+1] = size;
2340 if (rb->write(tfd, buf, MAX_PATH+2) != MAX_PATH+2)
2341 goto save_err;
2343 if (!viewer_write_preferences(tfd))
2344 goto save_err;
2346 if (!viewer_write_bookmark_infos(tfd))
2347 goto save_err;
2349 if (rb->lseek(tfd, SETTINGS_H_SIZE, SEEK_SET) < 0)
2350 goto save_err;
2352 fcount++;
2353 buf[0] = fcount >> 8;
2354 buf[1] = fcount;
2356 if (rb->write(tfd, buf, 2) != 2)
2357 goto save_err;
2359 rb->close(tfd);
2361 rb->remove(SETTINGS_FILE);
2362 rb->rename(SETTINGS_TMP_FILE, SETTINGS_FILE);
2364 return true;
2366 save_err:
2367 rb->close(tfd);
2368 rb->remove(SETTINGS_TMP_FILE);
2369 return false;
2372 static void viewer_exit(void *parameter)
2374 (void)parameter;
2376 /* save preference and bookmarks */
2377 if (!viewer_save_settings())
2378 rb->splash(HZ, "Can't save preference and bookmarks.");
2380 rb->close(fd);
2381 #ifdef HAVE_LCD_BITMAP
2382 if (rb->strcmp(prefs.font, rb->global_settings->font_file))
2383 change_font(rb->global_settings->font_file);
2384 #endif
2387 static void calc_page(void)
2389 int i;
2390 unsigned char *line_begin;
2391 unsigned char *line_end;
2392 off_t sfp;
2393 unsigned char *sstp;
2395 rb->splash(0, "Calculating page/line number...");
2397 /* add reading page to bookmarks */
2398 viewer_add_last_read_bookmark();
2400 rb->qsort(bookmarks, bookmark_count, sizeof(struct bookmark_info),
2401 bm_comp);
2403 cpage = 1;
2404 cline = 1;
2405 file_pos = 0;
2406 screen_top_ptr = buffer;
2407 buffer_end = BUFFER_END();
2409 fill_buffer(file_pos, buffer, buffer_size);
2410 line_end = line_begin = buffer;
2412 for (i = 0; i < bookmark_count; i++)
2414 sfp = bookmarks[i].file_position;
2415 sstp = buffer;
2417 while ((line_begin > sstp || sstp >= line_end) ||
2418 (file_pos > sfp || sfp >= file_pos + BUFFER_END() - buffer))
2420 get_next_line_position(&line_begin, &line_end, NULL);
2421 if (line_end == NULL)
2422 break;
2424 next_line_ptr = line_end;
2426 if (sstp == buffer &&
2427 file_pos <= sfp && sfp < file_pos + BUFFER_END() - buffer)
2428 sstp = sfp - file_pos + buffer;
2430 increment_current_line();
2433 decrement_current_line();
2434 bookmarks[i].page = cpage;
2435 bookmarks[i].line = cline;
2436 bookmarks[i].file_position = file_pos + (line_begin - buffer);
2437 increment_current_line();
2440 /* remove reading page's bookmark */
2441 for (i = 0; i < bookmark_count; i++)
2443 if (bookmarks[i].flag & BOOKMARK_LAST)
2445 int screen_pos;
2446 int screen_top;
2448 screen_pos = bookmarks[i].file_position;
2449 screen_top = screen_pos % buffer_size;
2450 file_pos = screen_pos - screen_top;
2451 screen_top_ptr = buffer + screen_top;
2453 cpage = bookmarks[i].page;
2454 cline = bookmarks[i].line;
2455 bookmarks[i].flag ^= BOOKMARK_LAST;
2456 buffer_end = BUFFER_END();
2458 fill_buffer(file_pos, buffer, buffer_size);
2460 if (bookmarks[i].flag == 0)
2461 viewer_remove_bookmark(i);
2463 if (prefs.scroll_mode == PAGE && cline > 1)
2464 viewer_scroll_to_top_line();
2465 break;
2470 static int col_limit(int col)
2472 if (col < 0)
2473 col = 0;
2474 else
2475 if (col >= max_width - draw_columns)
2476 col = max_width - draw_columns;
2478 return col;
2481 /* settings helper functions */
2483 static bool encoding_setting(void)
2485 static struct opt_items names[NUM_CODEPAGES];
2486 int idx;
2487 bool res;
2488 enum codepages oldenc = prefs.encoding;
2490 for (idx = 0; idx < NUM_CODEPAGES; idx++)
2492 names[idx].string = rb->get_codepage_name(idx);
2493 names[idx].voice_id = -1;
2496 res = rb->set_option("Encoding", &prefs.encoding, INT, names,
2497 sizeof(names) / sizeof(names[0]), NULL);
2499 /* When prefs.encoding changes into UTF-8 or changes from UTF-8,
2500 * filesize (file_size) might change.
2501 * In addition, if prefs.encoding is UTF-8, then BOM does not read.
2503 if (oldenc != prefs.encoding && (oldenc == UTF_8 || prefs.encoding == UTF_8))
2505 check_bom();
2506 get_filesize();
2507 fill_buffer(file_pos, buffer, buffer_size);
2510 return res;
2513 static bool word_wrap_setting(void)
2515 static const struct opt_items names[] = {
2516 {"On", -1},
2517 {"Off (Chop Words)", -1},
2520 return rb->set_option("Word Wrap", &prefs.word_mode, INT,
2521 names, 2, NULL);
2524 static bool line_mode_setting(void)
2526 static const struct opt_items names[] = {
2527 {"Normal", -1},
2528 {"Join Lines", -1},
2529 {"Expand Lines", -1},
2530 #ifdef HAVE_LCD_BITMAP
2531 {"Reflow Lines", -1},
2532 #endif
2535 return rb->set_option("Line Mode", &prefs.line_mode, INT, names,
2536 sizeof(names) / sizeof(names[0]), NULL);
2539 static bool view_mode_setting(void)
2541 static const struct opt_items names[] = {
2542 {"No (Narrow)", -1},
2543 {"Yes", -1},
2545 bool ret;
2546 ret = rb->set_option("Wide View", &prefs.view_mode, INT,
2547 names , 2, NULL);
2548 if (prefs.view_mode == NARROW)
2549 col = 0;
2550 calc_max_width();
2551 return ret;
2554 static bool scroll_mode_setting(void)
2556 static const struct opt_items names[] = {
2557 {"Scroll by Page", -1},
2558 {"Scroll by Line", -1},
2561 return rb->set_option("Scroll Mode", &prefs.scroll_mode, INT,
2562 names, 2, NULL);
2565 #ifdef HAVE_LCD_BITMAP
2566 static bool page_mode_setting(void)
2568 static const struct opt_items names[] = {
2569 {"No", -1},
2570 {"Yes", -1},
2573 return rb->set_option("Overlap Pages", &prefs.page_mode, INT,
2574 names, 2, NULL);
2577 static bool scrollbar_setting(void)
2579 static const struct opt_items names[] = {
2580 {"Off", -1},
2581 {"On", -1}
2584 return rb->set_option("Show Scrollbar", &prefs.scrollbar_mode, INT,
2585 names, 2, NULL);
2588 static bool header_setting(void)
2590 int len = (rb->global_settings->statusbar == STATUSBAR_TOP)? 4 : 2;
2591 struct opt_items names[len];
2593 names[0].string = "None";
2594 names[0].voice_id = -1;
2595 names[1].string = "File path";
2596 names[1].voice_id = -1;
2598 if (rb->global_settings->statusbar == STATUSBAR_TOP)
2600 names[2].string = "Status bar";
2601 names[2].voice_id = -1;
2602 names[3].string = "Both";
2603 names[3].voice_id = -1;
2606 return rb->set_option("Show Header", &prefs.header_mode, INT,
2607 names, len, NULL);
2610 static bool footer_setting(void)
2612 int len = (rb->global_settings->statusbar == STATUSBAR_BOTTOM)? 4 : 2;
2613 struct opt_items names[len];
2615 names[0].string = "None";
2616 names[0].voice_id = -1;
2617 names[1].string = "Page Num";
2618 names[1].voice_id = -1;
2620 if (rb->global_settings->statusbar == STATUSBAR_BOTTOM)
2622 names[2].string = "Status bar";
2623 names[2].voice_id = -1;
2624 names[3].string = "Both";
2625 names[3].voice_id = -1;
2628 return rb->set_option("Show Footer", &prefs.footer_mode, INT,
2629 names, len, NULL);
2632 static int font_comp(const void *a, const void *b)
2634 struct opt_items *pa;
2635 struct opt_items *pb;
2637 pa = (struct opt_items *)a;
2638 pb = (struct opt_items *)b;
2640 return rb->strcmp(pa->string, pb->string);
2643 static bool font_setting(void)
2645 int count = 0;
2646 DIR *dir;
2647 struct dirent *entry;
2648 int i = 0;
2649 int len;
2650 int new_font = 0;
2651 int old_font;
2652 bool res;
2653 int size = 0;
2655 dir = rb->opendir(FONT_DIR);
2656 if (!dir)
2658 rb->splash(HZ/2, "Font dir is not accessible");
2659 return false;
2662 while (1)
2664 entry = rb->readdir(dir);
2666 if (entry == NULL)
2667 break;
2669 len = rb->strlen(entry->d_name);
2670 if (len < 4 || rb->strcmp(entry->d_name + len-4, ".fnt"))
2671 continue;
2672 size += len-3;
2673 count++;
2675 rb->closedir(dir);
2677 struct opt_items names[count];
2678 unsigned char font_names[size];
2679 unsigned char *p = font_names;
2681 dir = rb->opendir(FONT_DIR);
2682 if (!dir)
2684 rb->splash(HZ/2, "Font dir is not accessible");
2685 return false;
2688 while (1)
2690 entry = rb->readdir(dir);
2692 if (entry == NULL)
2693 break;
2695 len = rb->strlen(entry->d_name);
2696 if (len < 4 || rb->strcmp(entry->d_name + len-4, ".fnt"))
2697 continue;
2699 rb->snprintf(p, len-3, "%s", entry->d_name);
2700 names[i].string = p;
2701 names[i].voice_id = -1;
2702 p += len-3;
2703 i++;
2704 if (i >= count)
2705 break;
2707 rb->closedir(dir);
2709 rb->qsort(names, count, sizeof(struct opt_items), font_comp);
2711 for (i = 0; i < count; i++)
2713 if (!rb->strcmp(names[i].string, prefs.font))
2715 new_font = i;
2716 break;
2719 old_font = new_font;
2721 res = rb->set_option("Select Font", &new_font, INT,
2722 names, count, NULL);
2724 if (new_font != old_font)
2726 /* load selected font */
2727 if (!change_font((unsigned char *)names[new_font].string)) {
2728 /* revert by re-loading the preferences font */
2729 change_font(prefs.font);
2730 return false;
2732 rb->memset(prefs.font, 0, MAX_PATH);
2733 rb->snprintf(prefs.font, MAX_PATH, "%s", names[new_font].string);
2736 return res;
2739 static bool alignment_setting(void)
2741 static const struct opt_items names[] = {
2742 {"Left", -1},
2743 {"Right", -1},
2746 return rb->set_option("Alignment", &prefs.alignment, INT,
2747 names , 2, NULL);
2749 #endif
2751 static bool autoscroll_speed_setting(void)
2753 return rb->set_int("Auto-scroll Speed", "", UNIT_INT,
2754 &prefs.autoscroll_speed, NULL, 1, 1, 10, NULL);
2757 MENUITEM_FUNCTION(encoding_item, 0, "Encoding", encoding_setting,
2758 NULL, NULL, Icon_NOICON);
2759 MENUITEM_FUNCTION(word_wrap_item, 0, "Word Wrap", word_wrap_setting,
2760 NULL, NULL, Icon_NOICON);
2761 MENUITEM_FUNCTION(line_mode_item, 0, "Line Mode", line_mode_setting,
2762 NULL, NULL, Icon_NOICON);
2763 MENUITEM_FUNCTION(view_mode_item, 0, "Wide View", view_mode_setting,
2764 NULL, NULL, Icon_NOICON);
2765 #ifdef HAVE_LCD_BITMAP
2766 MENUITEM_FUNCTION(alignment_item, 0, "Alignment", alignment_setting,
2767 NULL, NULL, Icon_NOICON);
2768 MENUITEM_FUNCTION(scrollbar_item, 0, "Show Scrollbar", scrollbar_setting,
2769 NULL, NULL, Icon_NOICON);
2770 MENUITEM_FUNCTION(page_mode_item, 0, "Overlap Pages", page_mode_setting,
2771 NULL, NULL, Icon_NOICON);
2772 MENUITEM_FUNCTION(header_item, 0, "Show Header", header_setting,
2773 NULL, NULL, Icon_NOICON);
2774 MENUITEM_FUNCTION(footer_item, 0, "Show Footer", footer_setting,
2775 NULL, NULL, Icon_NOICON);
2776 MENUITEM_FUNCTION(font_item, 0, "Font", font_setting,
2777 NULL, NULL, Icon_NOICON);
2778 #endif
2779 MENUITEM_FUNCTION(scroll_mode_item, 0, "Scroll Mode", scroll_mode_setting,
2780 NULL, NULL, Icon_NOICON);
2781 MENUITEM_FUNCTION(autoscroll_speed_item, 0, "Auto-Scroll Speed",
2782 autoscroll_speed_setting, NULL, NULL, Icon_NOICON);
2783 MAKE_MENU(option_menu, "Viewer Options", NULL, Icon_NOICON,
2784 &encoding_item, &word_wrap_item, &line_mode_item, &view_mode_item,
2785 #ifdef HAVE_LCD_BITMAP
2786 &alignment_item, &scrollbar_item, &page_mode_item, &header_item,
2787 &footer_item, &font_item,
2788 #endif
2789 &scroll_mode_item, &autoscroll_speed_item);
2791 static bool viewer_options_menu(bool is_global)
2793 bool result;
2794 struct preferences tmp_prefs;
2796 rb->memcpy(&tmp_prefs, &prefs, sizeof(struct preferences));
2798 result = (rb->do_menu(&option_menu, NULL, NULL, false) == MENU_ATTACHED_USB);
2800 if (!is_global && rb->memcmp(&tmp_prefs, &prefs, sizeof(struct preferences)))
2802 /* Show-scrollbar mode for current view-width mode */
2803 #ifdef HAVE_LCD_BITMAP
2804 init_need_scrollbar();
2805 init_header_and_footer();
2806 #endif
2807 calc_page();
2809 return result;
2812 static void viewer_menu(void)
2814 int result;
2816 MENUITEM_STRINGLIST(menu, "Viewer Menu", NULL,
2817 "Return", "Viewer Options",
2818 "Show Playback Menu", "Select Bookmark",
2819 "Global Settings", "Quit");
2821 result = rb->do_menu(&menu, NULL, NULL, false);
2822 switch (result)
2824 case 0: /* return */
2825 break;
2826 case 1: /* change settings */
2827 done = viewer_options_menu(false);
2828 break;
2829 case 2: /* playback control */
2830 playback_control(NULL);
2831 break;
2832 case 3: /* select bookmark */
2833 viewer_select_bookmark(viewer_add_last_read_bookmark());
2834 viewer_remove_last_read_bookmark();
2835 fill_buffer(file_pos, buffer, buffer_size);
2836 if (prefs.scroll_mode == PAGE && cline > 1)
2837 viewer_scroll_to_top_line();
2838 break;
2839 case 4: /* change global settings */
2841 struct preferences orig_prefs;
2843 rb->memcpy(&orig_prefs, &prefs, sizeof(struct preferences));
2844 if (!viewer_load_global_settings())
2845 viewer_default_preferences();
2846 done = viewer_options_menu(true);
2847 viewer_save_global_settings();
2848 rb->memcpy(&prefs, &orig_prefs, sizeof(struct preferences));
2850 break;
2851 case 5: /* quit */
2852 viewer_exit(NULL);
2853 done = true;
2854 break;
2856 viewer_draw(col);
2859 enum plugin_status plugin_start(const void* file)
2861 int button, i, ok;
2862 int lastbutton = BUTTON_NONE;
2863 bool autoscroll = false;
2864 long old_tick;
2866 old_tick = *rb->current_tick;
2868 /* get the plugin buffer */
2869 buffer = rb->plugin_get_buffer((size_t *)&buffer_size);
2870 if (buffer_size == 0)
2872 rb->splash(HZ, "buffer does not allocate !!");
2873 return PLUGIN_ERROR;
2875 block_size = buffer_size / 3;
2876 buffer_size = 3 * block_size;
2878 if (!file)
2879 return PLUGIN_ERROR;
2881 file_name = file;
2882 ok = viewer_init();
2883 if (!ok) {
2884 rb->splash(HZ, "Error opening file.");
2885 return PLUGIN_ERROR;
2888 if (!viewer_load_settings()) /* load the preferences and bookmark */
2889 return PLUGIN_ERROR;
2891 #if LCD_DEPTH > 1
2892 rb->lcd_set_backdrop(NULL);
2893 #endif
2895 viewer_draw(col);
2897 while (!done) {
2899 if(autoscroll)
2901 if(old_tick <= *rb->current_tick - (110-prefs.autoscroll_speed*10))
2903 viewer_scroll_down(true);
2904 viewer_draw(col);
2905 old_tick = *rb->current_tick;
2909 button = rb->button_get_w_tmo(HZ/10);
2911 if (prefs.view_mode != WIDE) {
2912 /* when not in wide view mode, the SCREEN_LEFT and SCREEN_RIGHT
2913 buttons jump to the beginning and end of the file. To stop
2914 users doing this by accident, replace non-held occurrences
2915 with page up/down instead. */
2916 if (button == VIEWER_SCREEN_LEFT)
2917 button = VIEWER_PAGE_UP;
2918 else if (button == VIEWER_SCREEN_RIGHT)
2919 button = VIEWER_PAGE_DOWN;
2922 switch (button) {
2923 case VIEWER_MENU:
2924 #ifdef VIEWER_MENU2
2925 case VIEWER_MENU2:
2926 #endif
2927 viewer_menu();
2928 break;
2930 case VIEWER_AUTOSCROLL:
2931 #ifdef VIEWER_AUTOSCROLL_PRE
2932 if (lastbutton != VIEWER_AUTOSCROLL_PRE)
2933 break;
2934 #endif
2935 autoscroll = !autoscroll;
2936 break;
2938 case VIEWER_PAGE_UP:
2939 case VIEWER_PAGE_UP | BUTTON_REPEAT:
2940 #ifdef VIEWER_PAGE_UP2
2941 case VIEWER_PAGE_UP2:
2942 case VIEWER_PAGE_UP2 | BUTTON_REPEAT:
2943 #endif
2944 if (prefs.scroll_mode == PAGE)
2946 /* Page up */
2947 #ifdef HAVE_LCD_BITMAP
2948 for (i = prefs.page_mode==OVERLAP? 1:0; i < display_lines; i++)
2949 #else
2950 for (i = 0; i < display_lines; i++)
2951 #endif
2952 viewer_scroll_up();
2954 else
2955 viewer_scroll_up();
2956 old_tick = *rb->current_tick;
2957 viewer_draw(col);
2958 break;
2960 case VIEWER_PAGE_DOWN:
2961 case VIEWER_PAGE_DOWN | BUTTON_REPEAT:
2962 #ifdef VIEWER_PAGE_DOWN2
2963 case VIEWER_PAGE_DOWN2:
2964 case VIEWER_PAGE_DOWN2 | BUTTON_REPEAT:
2965 #endif
2966 if (prefs.scroll_mode == PAGE)
2968 /* Page down */
2969 if (next_screen_ptr != NULL)
2971 screen_top_ptr = next_screen_to_draw_ptr;
2972 if (cpage < MAX_PAGE)
2973 cpage++;
2976 else
2977 viewer_scroll_down(autoscroll);
2978 old_tick = *rb->current_tick;
2979 viewer_draw(col);
2980 break;
2982 case VIEWER_SCREEN_LEFT:
2983 case VIEWER_SCREEN_LEFT | BUTTON_REPEAT:
2984 if (prefs.view_mode == WIDE) {
2985 /* Screen left */
2986 col = col_limit(col - draw_columns);
2988 else { /* prefs.view_mode == NARROW */
2989 /* Top of file */
2990 viewer_top();
2993 viewer_draw(col);
2994 break;
2996 case VIEWER_SCREEN_RIGHT:
2997 case VIEWER_SCREEN_RIGHT | BUTTON_REPEAT:
2998 if (prefs.view_mode == WIDE) {
2999 /* Screen right */
3000 col = col_limit(col + draw_columns);
3002 else { /* prefs.view_mode == NARROW */
3003 /* Bottom of file */
3004 viewer_bottom();
3007 viewer_draw(col);
3008 break;
3010 #ifdef VIEWER_LINE_UP
3011 case VIEWER_LINE_UP:
3012 case VIEWER_LINE_UP | BUTTON_REPEAT:
3013 /* Scroll up one line */
3014 viewer_scroll_up();
3015 old_tick = *rb->current_tick;
3016 viewer_draw(col);
3017 break;
3019 case VIEWER_LINE_DOWN:
3020 case VIEWER_LINE_DOWN | BUTTON_REPEAT:
3021 /* Scroll down one line */
3022 viewer_scroll_down(autoscroll);
3023 increment_current_line();
3024 old_tick = *rb->current_tick;
3025 viewer_draw(col);
3026 break;
3027 #endif
3028 #ifdef VIEWER_COLUMN_LEFT
3029 case VIEWER_COLUMN_LEFT:
3030 case VIEWER_COLUMN_LEFT | BUTTON_REPEAT:
3031 if (prefs.view_mode == WIDE) {
3032 /* Scroll left one column */
3033 col = col_limit(col - glyph_width('o'));
3034 viewer_draw(col);
3036 break;
3038 case VIEWER_COLUMN_RIGHT:
3039 case VIEWER_COLUMN_RIGHT | BUTTON_REPEAT:
3040 if (prefs.view_mode == WIDE) {
3041 /* Scroll right one column */
3042 col = col_limit(col + glyph_width('o'));
3043 viewer_draw(col);
3045 break;
3046 #endif
3048 #ifdef VIEWER_RC_QUIT
3049 case VIEWER_RC_QUIT:
3050 #endif
3051 case VIEWER_QUIT:
3052 #ifdef VIEWER_QUIT2
3053 case VIEWER_QUIT2:
3054 #endif
3055 viewer_exit(NULL);
3056 done = true;
3057 break;
3059 case VIEWER_BOOKMARK:
3061 int idx = viewer_find_bookmark(cpage, cline);
3063 if (idx < 0)
3065 if (bookmark_count >= MAX_BOOKMARKS-1)
3066 rb->splash(HZ/2, "No more add bookmark.");
3067 else
3069 viewer_add_bookmark();
3070 rb->splash(HZ/2, "Bookmark add.");
3073 else
3075 viewer_remove_bookmark(idx);
3076 rb->splash(HZ/2, "Bookmark remove.");
3078 viewer_draw(col);
3080 break;
3082 default:
3083 if (rb->default_event_handler_ex(button, viewer_exit, NULL)
3084 == SYS_USB_CONNECTED)
3085 return PLUGIN_USB_CONNECTED;
3086 break;
3088 if (button != BUTTON_NONE)
3090 lastbutton = button;
3091 rb->yield();
3094 return PLUGIN_OK;