1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 Gilles Roux, 2003 Garrett Derner
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 #include "lib/playback_control.h"
27 /* global settings file
28 * binary file, so dont use .cfg
33 * --------------------------------
50 #define GLOBAL_SETTINGS_FILE VIEWERS_DIR "/viewer.dat"
53 #define GLOBAL_SETTINGS_TMP_FILE VIEWERS_DIR "/viewer_file.tmp"
55 #define GLOBAL_SETTINGS_HEADER "\x54\x56\x47\x53" /* header="TVGS" */
56 #define GLOBAL_SETTINGS_H_SIZE 5
57 #define GLOBAL_SETTINGS_VERSION 0x32 /* version=2 */
58 #define GLOBAL_SETTINGS_FIRST_VERSION 0x31
60 /* preferences and bookmarks at each file
61 * binary file, so dont use .cfg
66 * --------------------------------
100 #define SETTINGS_FILE VIEWERS_DIR "/viewer_file.dat"
103 #define SETTINGS_TMP_FILE VIEWERS_DIR "/viewer_file.tmp"
105 #define SETTINGS_HEADER "\x54\x56\x53" /* header="TVS" */
106 #define SETTINGS_H_SIZE 4
107 #define SETTINGS_VERSION 0x33 /* version=3 */
108 #define SETTINGS_FIRST_VERSION 0x32
110 #define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */
111 #define NARROW_MAX_COLUMNS 64 /* Max displayable string len [narrow] (over-estimate) */
112 #define WIDE_MAX_COLUMNS 128 /* Max displayable string len [wide] (over-estimate) */
113 #define MAX_WIDTH 910 /* Max line length in WIDE mode */
114 #define READ_PREV_ZONE (block_size*9/10) /* Arbitrary number less than SMALL_BLOCK_SIZE */
115 #define SMALL_BLOCK_SIZE block_size /* Smallest file chunk we will read */
116 #define LARGE_BLOCK_SIZE (block_size << 1) /* Preferable size of file chunk to read */
117 #define TOP_SECTOR buffer
118 #define MID_SECTOR (buffer + SMALL_BLOCK_SIZE)
119 #define BOTTOM_SECTOR (buffer + (SMALL_BLOCK_SIZE << 1))
120 #undef SCROLLBAR_WIDTH
121 #define SCROLLBAR_WIDTH rb->global_settings->scrollbar_width
122 #define MAX_PAGE 9999
124 #define BOOKMARK_SIZE 8
125 #define MAX_BOOKMARKS 10 /* user setting bookmarks + last read page */
127 #define BOOKMARK_LAST 1
128 #define BOOKMARK_USER 2
130 #ifndef HAVE_LCD_BITMAP
131 #define BOOKMARK_ICON "\xee\x84\x81\x00"
134 #define PREFERENCES_SIZE (12 + MAX_PATH)
136 /* Out-Of-Bounds test for any pointer to data in the buffer */
137 #define BUFFER_OOB(p) ((p) < buffer || (p) >= buffer_end)
139 /* Does the buffer contain the beginning of the file? */
140 #define BUFFER_BOF() (file_pos==0)
142 /* Does the buffer contain the end of the file? */
143 #define BUFFER_EOF() (file_size-file_pos <= buffer_size)
145 /* Formula for the endpoint address outside of buffer data */
146 #define BUFFER_END() \
147 ((BUFFER_EOF()) ? (file_size-file_pos+buffer) : (buffer+buffer_size))
149 /* Is the entire file being shown in one screen? */
150 #define ONE_SCREEN_FITS_ALL() \
151 (next_screen_ptr==NULL && screen_top_ptr==buffer && BUFFER_BOF())
153 /* Is a scrollbar called for on the current screen? */
154 #define NEED_SCROLLBAR() \
155 ((!(ONE_SCREEN_FITS_ALL())) && (prefs.scrollbar_mode==SB_ON))
157 /* variable button definitions */
160 #if CONFIG_KEYPAD == RECORDER_PAD
161 #define VIEWER_QUIT BUTTON_OFF
162 #define VIEWER_PAGE_UP BUTTON_UP
163 #define VIEWER_PAGE_DOWN BUTTON_DOWN
164 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
165 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
166 #define VIEWER_MENU BUTTON_F1
167 #define VIEWER_AUTOSCROLL BUTTON_PLAY
168 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
169 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
170 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
171 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
172 #define VIEWER_BOOKMARK BUTTON_F2
174 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
175 #define VIEWER_QUIT BUTTON_OFF
176 #define VIEWER_PAGE_UP BUTTON_UP
177 #define VIEWER_PAGE_DOWN BUTTON_DOWN
178 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
179 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
180 #define VIEWER_MENU BUTTON_F1
181 #define VIEWER_AUTOSCROLL BUTTON_SELECT
182 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
183 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
184 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
185 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
186 #define VIEWER_BOOKMARK BUTTON_F2
189 #elif CONFIG_KEYPAD == ONDIO_PAD
190 #define VIEWER_QUIT BUTTON_OFF
191 #define VIEWER_PAGE_UP BUTTON_UP
192 #define VIEWER_PAGE_DOWN BUTTON_DOWN
193 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
194 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
195 #define VIEWER_MENU (BUTTON_MENU|BUTTON_REPEAT)
196 #define VIEWER_AUTOSCROLL_PRE BUTTON_MENU
197 #define VIEWER_AUTOSCROLL (BUTTON_MENU|BUTTON_REL)
198 #define VIEWER_BOOKMARK (BUTTON_MENU|BUTTON_OFF)
201 #elif CONFIG_KEYPAD == PLAYER_PAD
202 #define VIEWER_QUIT BUTTON_STOP
203 #define VIEWER_PAGE_UP BUTTON_LEFT
204 #define VIEWER_PAGE_DOWN BUTTON_RIGHT
205 #define VIEWER_SCREEN_LEFT (BUTTON_ON|BUTTON_LEFT)
206 #define VIEWER_SCREEN_RIGHT (BUTTON_ON|BUTTON_RIGHT)
207 #define VIEWER_MENU BUTTON_MENU
208 #define VIEWER_AUTOSCROLL BUTTON_PLAY
209 #define VIEWER_BOOKMARK BUTTON_ON
211 /* iRiver H1x0 && H3x0 keys */
212 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
213 (CONFIG_KEYPAD == IRIVER_H300_PAD)
214 #define VIEWER_QUIT BUTTON_OFF
215 #define VIEWER_PAGE_UP BUTTON_UP
216 #define VIEWER_PAGE_DOWN BUTTON_DOWN
217 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
218 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
219 #define VIEWER_MENU BUTTON_MODE
220 #define VIEWER_AUTOSCROLL BUTTON_SELECT
221 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
222 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
223 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
224 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
225 #define VIEWER_BOOKMARK (BUTTON_ON | BUTTON_SELECT)
227 #define VIEWER_RC_QUIT BUTTON_RC_STOP
230 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
231 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
232 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
233 #define VIEWER_QUIT_PRE BUTTON_SELECT
234 #define VIEWER_QUIT (BUTTON_SELECT | BUTTON_MENU)
235 #define VIEWER_PAGE_UP BUTTON_SCROLL_BACK
236 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_FWD
237 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
238 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
239 #define VIEWER_MENU BUTTON_MENU
240 #define VIEWER_AUTOSCROLL BUTTON_PLAY
241 #define VIEWER_BOOKMARK BUTTON_SELECT
244 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
245 #define VIEWER_QUIT BUTTON_PLAY
246 #define VIEWER_PAGE_UP BUTTON_UP
247 #define VIEWER_PAGE_DOWN BUTTON_DOWN
248 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
249 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
250 #define VIEWER_MENU BUTTON_MODE
251 #define VIEWER_AUTOSCROLL BUTTON_SELECT
252 #define VIEWER_BOOKMARK (BUTTON_LEFT|BUTTON_SELECT)
255 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
256 #define VIEWER_QUIT BUTTON_POWER
257 #define VIEWER_PAGE_UP BUTTON_UP
258 #define VIEWER_PAGE_DOWN BUTTON_DOWN
259 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
260 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
261 #define VIEWER_MENU BUTTON_SELECT
262 #define VIEWER_AUTOSCROLL BUTTON_PLAY
263 #define VIEWER_BOOKMARK BUTTON_REC
266 #elif CONFIG_KEYPAD == GIGABEAT_PAD
267 #define VIEWER_QUIT BUTTON_POWER
268 #define VIEWER_PAGE_UP BUTTON_UP
269 #define VIEWER_PAGE_DOWN BUTTON_DOWN
270 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
271 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
272 #define VIEWER_MENU BUTTON_MENU
273 #define VIEWER_AUTOSCROLL BUTTON_A
274 #define VIEWER_BOOKMARK BUTTON_SELECT
276 /* Sansa E200 keys */
277 #elif CONFIG_KEYPAD == SANSA_E200_PAD
278 #define VIEWER_QUIT BUTTON_POWER
279 #define VIEWER_PAGE_UP BUTTON_UP
280 #define VIEWER_PAGE_DOWN BUTTON_DOWN
281 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
282 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
283 #define VIEWER_MENU BUTTON_SELECT
284 #define VIEWER_AUTOSCROLL BUTTON_REC
285 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
286 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
287 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
289 /* Sansa Fuze keys */
290 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
291 #define VIEWER_QUIT (BUTTON_HOME|BUTTON_REPEAT)
292 #define VIEWER_PAGE_UP BUTTON_UP
293 #define VIEWER_PAGE_DOWN BUTTON_DOWN
294 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
295 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
296 #define VIEWER_MENU BUTTON_SELECT|BUTTON_REPEAT
297 #define VIEWER_AUTOSCROLL BUTTON_SELECT|BUTTON_DOWN
298 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
299 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
300 #define VIEWER_BOOKMARK BUTTON_SELECT
302 /* Sansa C200 keys */
303 #elif CONFIG_KEYPAD == SANSA_C200_PAD
304 #define VIEWER_QUIT BUTTON_POWER
305 #define VIEWER_PAGE_UP BUTTON_VOL_UP
306 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
307 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
308 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
309 #define VIEWER_MENU BUTTON_SELECT
310 #define VIEWER_AUTOSCROLL BUTTON_REC
311 #define VIEWER_LINE_UP BUTTON_UP
312 #define VIEWER_LINE_DOWN BUTTON_DOWN
313 #define VIEWER_BOOKMARK (BUTTON_DOWN | BUTTON_SELECT)
315 /* Sansa Clip keys */
316 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
317 #define VIEWER_QUIT BUTTON_POWER
318 #define VIEWER_PAGE_UP BUTTON_VOL_UP
319 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
320 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
321 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
322 #define VIEWER_MENU BUTTON_SELECT
323 #define VIEWER_AUTOSCROLL BUTTON_HOME
324 #define VIEWER_LINE_UP BUTTON_UP
325 #define VIEWER_LINE_DOWN BUTTON_DOWN
326 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
328 /* Sansa M200 keys */
329 #elif CONFIG_KEYPAD == SANSA_M200_PAD
330 #define VIEWER_QUIT BUTTON_POWER
331 #define VIEWER_PAGE_UP BUTTON_VOL_UP
332 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
333 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
334 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
335 #define VIEWER_MENU (BUTTON_SELECT | BUTTON_UP)
336 #define VIEWER_AUTOSCROLL (BUTTON_SELECT | BUTTON_REL)
337 #define VIEWER_LINE_UP BUTTON_UP
338 #define VIEWER_LINE_DOWN BUTTON_DOWN
339 #define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT)
341 /* iriver H10 keys */
342 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
343 #define VIEWER_QUIT BUTTON_POWER
344 #define VIEWER_PAGE_UP BUTTON_SCROLL_UP
345 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_DOWN
346 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
347 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
348 #define VIEWER_MENU BUTTON_REW
349 #define VIEWER_AUTOSCROLL BUTTON_PLAY
350 #define VIEWER_BOOKMARK BUTTON_FF
353 #elif CONFIG_KEYPAD == MROBE500_PAD
354 #define VIEWER_QUIT BUTTON_POWER
355 #define VIEWER_PAGE_UP BUTTON_RC_PLAY
356 #define VIEWER_PAGE_DOWN BUTTON_RC_DOWN
357 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
358 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
359 #define VIEWER_MENU BUTTON_RC_HEART
360 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
361 #define VIEWER_BOOKMARK BUTTON_CENTER
364 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
365 #define VIEWER_QUIT BUTTON_BACK
366 #define VIEWER_PAGE_UP BUTTON_PREV
367 #define VIEWER_PAGE_DOWN BUTTON_NEXT
368 #define VIEWER_SCREEN_LEFT (BUTTON_PLAY | BUTTON_LEFT)
369 #define VIEWER_SCREEN_RIGHT (BUTTON_PLAY | BUTTON_RIGHT)
370 #define VIEWER_MENU BUTTON_MENU
371 #define VIEWER_AUTOSCROLL_PRE BUTTON_PLAY
372 #define VIEWER_AUTOSCROLL (BUTTON_PLAY|BUTTON_REL)
373 #define VIEWER_LINE_UP BUTTON_UP
374 #define VIEWER_LINE_DOWN BUTTON_DOWN
375 #define VIEWER_COLUMN_LEFT BUTTON_LEFT
376 #define VIEWER_COLUMN_RIGHT BUTTON_RIGHT
377 #define VIEWER_BOOKMARK BUTTON_SELECT
380 #elif CONFIG_KEYPAD == MROBE100_PAD
381 #define VIEWER_QUIT BUTTON_POWER
382 #define VIEWER_PAGE_UP BUTTON_UP
383 #define VIEWER_PAGE_DOWN BUTTON_DOWN
384 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
385 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
386 #define VIEWER_MENU BUTTON_MENU
387 #define VIEWER_AUTOSCROLL BUTTON_DISPLAY
388 #define VIEWER_BOOKMARK BUTTON_SELECT
391 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
392 #define VIEWER_QUIT BUTTON_REC
393 #define VIEWER_PAGE_UP BUTTON_RC_VOL_UP
394 #define VIEWER_PAGE_DOWN BUTTON_RC_VOL_DOWN
395 #define VIEWER_SCREEN_LEFT BUTTON_RC_REW
396 #define VIEWER_SCREEN_RIGHT BUTTON_RC_FF
397 #define VIEWER_MENU BUTTON_RC_MENU
398 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
399 #define VIEWER_RC_QUIT BUTTON_RC_REC
400 #define VIEWER_BOOKMARK BUTTON_RC_PLAY
403 #elif CONFIG_KEYPAD == COWON_D2_PAD
404 #define VIEWER_QUIT BUTTON_POWER
405 #define VIEWER_MENU BUTTON_MENU
406 #define VIEWER_PAGE_UP BUTTON_MINUS
407 #define VIEWER_PAGE_DOWN BUTTON_PLUS
408 #define VIEWER_BOOKMARK (BUTTON_MENU|BUTTON_PLUS)
410 #elif CONFIG_KEYPAD == IAUDIO67_PAD
411 #define VIEWER_QUIT BUTTON_POWER
412 #define VIEWER_PAGE_UP BUTTON_VOLUP
413 #define VIEWER_PAGE_DOWN BUTTON_VOLDOWN
414 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
415 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
416 #define VIEWER_MENU BUTTON_MENU
417 #define VIEWER_AUTOSCROLL BUTTON_PLAY
418 #define VIEWER_RC_QUIT BUTTON_STOP
419 #define VIEWER_BOOKMARK (BUTTON_LEFT|BUTTON_PLAY)
421 /* Creative Zen Vision:M keys */
422 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
423 #define VIEWER_QUIT BUTTON_BACK
424 #define VIEWER_PAGE_UP BUTTON_UP
425 #define VIEWER_PAGE_DOWN BUTTON_DOWN
426 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
427 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
428 #define VIEWER_MENU BUTTON_MENU
429 #define VIEWER_AUTOSCROLL BUTTON_SELECT
430 #define VIEWER_BOOKMARK BUTTON_PLAY
432 /* Philips HDD1630 keys */
433 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
434 #define VIEWER_QUIT BUTTON_POWER
435 #define VIEWER_PAGE_UP BUTTON_UP
436 #define VIEWER_PAGE_DOWN BUTTON_DOWN
437 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
438 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
439 #define VIEWER_MENU BUTTON_MENU
440 #define VIEWER_AUTOSCROLL BUTTON_VIEW
441 #define VIEWER_BOOKMARK BUTTON_SELECT
443 /* Philips SA9200 keys */
444 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
445 #define VIEWER_QUIT BUTTON_POWER
446 #define VIEWER_PAGE_UP BUTTON_UP
447 #define VIEWER_PAGE_DOWN BUTTON_DOWN
448 #define VIEWER_SCREEN_LEFT BUTTON_PREV
449 #define VIEWER_SCREEN_RIGHT BUTTON_NEXT
450 #define VIEWER_MENU BUTTON_MENU
451 #define VIEWER_AUTOSCROLL BUTTON_PLAY
452 #define VIEWER_BOOKMARK BUTTON_RIGHT
454 /* Onda VX747 keys */
455 #elif CONFIG_KEYPAD == ONDAVX747_PAD
456 #define VIEWER_QUIT BUTTON_POWER
457 #define VIEWER_MENU BUTTON_MENU
458 #define VIEWER_BOOKMARK (BUTTON_RIGHT|BUTTON_POWER)
460 /* Onda VX777 keys */
461 #elif CONFIG_KEYPAD == ONDAVX777_PAD
462 #define VIEWER_QUIT BUTTON_POWER
463 #define VIEWER_BOOKMARK (BUTTON_RIGHT|BUTTON_POWER)
465 /* SAMSUNG YH-820 / YH-920 / YH-925 keys */
466 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
467 #define VIEWER_QUIT BUTTON_REC
468 #define VIEWER_PAGE_UP BUTTON_UP
469 #define VIEWER_PAGE_DOWN BUTTON_DOWN
470 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
471 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
472 #define VIEWER_MENU BUTTON_PLAY
473 #define VIEWER_AUTOSCROLL BUTTON_REW
474 #define VIEWER_BOOKMARK BUTTON_FFWD
476 /* Packard Bell Vibe 500 keys */
477 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
478 #define VIEWER_QUIT BUTTON_REC
479 #define VIEWER_PAGE_UP BUTTON_OK
480 #define VIEWER_PAGE_DOWN BUTTON_CANCEL
481 #define VIEWER_LINE_UP BUTTON_UP
482 #define VIEWER_LINE_DOWN BUTTON_DOWN
483 #define VIEWER_SCREEN_LEFT BUTTON_PREV
484 #define VIEWER_SCREEN_RIGHT BUTTON_NEXT
485 #define VIEWER_MENU BUTTON_MENU
486 #define VIEWER_AUTOSCROLL BUTTON_PLAY
487 #define VIEWER_BOOKMARK BUTTON_POWER
490 #error No keymap defined!
493 #ifdef HAVE_TOUCHSCREEN
495 #define VIEWER_QUIT2 BUTTON_TOPLEFT
497 #define VIEWER_QUIT BUTTON_TOPLEFT
499 #ifdef VIEWER_PAGE_UP
500 #define VIEWER_PAGE_UP2 BUTTON_TOPMIDDLE
502 #define VIEWER_PAGE_UP BUTTON_TOPMIDDLE
504 #ifdef VIEWER_PAGE_DOWN
505 #define VIEWER_PAGE_DOWN2 BUTTON_BOTTOMMIDDLE
507 #define VIEWER_PAGE_DOWN BUTTON_BOTTOMMIDDLE
509 #ifndef VIEWER_SCREEN_LEFT
510 #define VIEWER_SCREEN_LEFT BUTTON_MIDLEFT
512 #ifndef VIEWER_SCREEN_RIGHT
513 #define VIEWER_SCREEN_RIGHT BUTTON_MIDRIGHT
516 #define VIEWER_MENU2 BUTTON_TOPRIGHT
518 #define VIEWER_MENU BUTTON_TOPRIGHT
520 #ifndef VIEWER_AUTOSCROLL
521 #define VIEWER_AUTOSCROLL BUTTON_CENTER
525 /* stuff for the bookmarking */
526 struct bookmark_info
{
543 REFLOW
, /* won't be set on charcell LCD, must be last */
556 enum codepages encoding
;
588 int autoscroll_speed
;
590 unsigned char font
[MAX_PATH
];
594 VIEWER_FONT_MENU
= 0,
598 struct preferences prefs
;
599 struct preferences old_prefs
;
601 static unsigned char *buffer
;
602 static long buffer_size
;
603 static long block_size
= 0x1000;
604 static unsigned char line_break
[] = {0,0x20,9,0xB,0xC,'-'};
605 static int display_columns
; /* number of (pixel) columns on the display */
606 static int display_lines
; /* number of lines on the display */
607 static int draw_columns
; /* number of (pixel) columns available for text */
608 static int par_indent_spaces
; /* number of spaces to indent first paragraph */
610 static const char *file_name
;
611 static long file_size
;
612 static long start_position
; /* position in the file after the viewer is started */
613 static bool mac_text
;
614 static long file_pos
; /* Position of the top of the buffer in the file */
615 static long last_file_pos
;
616 static unsigned char *buffer_end
; /*Set to BUFFER_END() when file_pos changes*/
617 static int max_line_len
;
618 static int max_width
;
619 static int max_columns
;
620 static int cline
= 1;
621 static int cpage
= 1;
622 static int lpage
= 0;
623 static unsigned char *screen_top_ptr
;
624 static unsigned char *next_screen_ptr
;
625 static unsigned char *next_screen_to_draw_ptr
;
626 static unsigned char *next_line_ptr
;
627 static unsigned char *last_screen_top_ptr
= NULL
;
628 #ifdef HAVE_LCD_BITMAP
629 static struct font
*pf
;
630 static int header_height
= 0;
631 static int footer_height
= 0;
633 struct bookmark_info bookmarks
[MAX_BOOKMARKS
];
634 static int bookmark_count
;
637 #define BOM "\xef\xbb\xbf"
640 static bool is_bom
= false;
642 /* calculate the width of a UCS character (zero width for diacritics) */
643 static int glyph_width(unsigned short ch
)
648 #ifdef HAVE_LCD_BITMAP
649 if (rb
->is_diacritic(ch
, NULL
))
652 return rb
->font_get_width(pf
, ch
);
658 /* get UCS character from string */
659 static unsigned char* get_ucs(const unsigned char* str
, unsigned short* ch
)
661 unsigned char utf8_tmp
[6];
664 if (prefs
.encoding
== UTF_8
)
665 return (unsigned char*)rb
->utf8decode(str
, ch
);
667 count
= BUFFER_OOB(str
+2)? 1:2;
668 rb
->iso_decode(str
, utf8_tmp
, prefs
.encoding
, count
);
669 rb
->utf8decode(utf8_tmp
, ch
);
671 /* return a pointer after the parsed section of the string */
672 #ifdef HAVE_LCD_BITMAP
673 if (prefs
.encoding
>= SJIS
&& *str
>= 0x80
674 && !(prefs
.encoding
== SJIS
&& *str
> 0xA0 && *str
< 0xE0))
675 return (unsigned char*)str
+2;
678 return (unsigned char*)str
+1;
681 /* decode UCS string into UTF-8 string */
682 static unsigned char *decode2utf8(const unsigned char *src
, unsigned char *dst
,
683 int skip_width
, int disp_width
)
686 const unsigned char *oldstr
;
687 const unsigned char *str
= src
;
688 unsigned char *utf8
= dst
;
691 /* skip the skip_width */
695 str
= get_ucs(oldstr
, &ch
);
696 width
+= glyph_width(ch
);
697 if (width
> skip_width
)
704 /* decode until string end or disp_width reached */
708 str
= get_ucs(str
, &ch
);
709 width
+= glyph_width(ch
);
710 if (width
> disp_width
)
713 utf8
= rb
->utf8encode(ch
, utf8
);
716 /* return a pointer after the dst string ends */
720 /* set max_columns and max_width */
721 static void calc_max_width(void)
723 if (prefs
.view_mode
== NARROW
)
725 max_columns
= NARROW_MAX_COLUMNS
;
726 max_width
= draw_columns
;
730 max_columns
= WIDE_MAX_COLUMNS
;
731 max_width
= 2 * draw_columns
;
735 static bool done
= false;
738 static inline void advance_conters(unsigned short ch
, int* k
, int* width
)
740 #ifdef HAVE_LCD_BITMAP
741 /* diacritics do not count */
742 if (rb
->is_diacritic(ch
, NULL
))
746 *width
+= glyph_width(ch
);
750 static inline bool line_is_full(int k
, int width
)
752 return ((k
>= max_columns
- 1) || (width
>= max_width
));
755 static unsigned char* crop_at_width(const unsigned char* p
)
759 const unsigned char *oldp
= p
;
763 while (!line_is_full(k
, width
)) {
768 advance_conters(ch
, &k
, &width
);
771 return (unsigned char*)oldp
;
774 static unsigned char* find_first_feed(const unsigned char* p
, int size
)
778 const unsigned char *oldp
= p
;
783 return (unsigned char*)p
;
792 static unsigned char* find_last_feed(const unsigned char* p
, int size
)
796 for (i
=size
-1; i
>=0; i
--)
798 return (unsigned char*) p
+i
;
803 static unsigned char* find_last_space(const unsigned char* p
, int size
)
807 k
= (prefs
.line_mode
==JOIN
) || (prefs
.line_mode
==REFLOW
) ? 0:1;
810 if (!BUFFER_OOB(&p
[i
]))
811 for (j
=k
; j
< ((int) sizeof(line_break
)) - 1; j
++) {
812 if (p
[i
] == line_break
[j
])
813 return (unsigned char*) p
+i
;
816 if (prefs
.word_mode
== WRAP
) {
817 for (i
=size
-1; i
>=0; i
--) {
818 for (j
=k
; j
< (int) sizeof(line_break
) - 1; j
++) {
819 if (p
[i
] == line_break
[j
])
820 return (unsigned char*) p
+i
;
828 static unsigned char* find_next_line(const unsigned char* cur_line
, bool *is_short
)
830 const unsigned char *next_line
= NULL
;
831 int size
, i
, j
, j_next
, j_prev
, k
, width
, search_len
, spaces
, newlines
;
835 if (is_short
!= NULL
)
838 if BUFFER_OOB(cur_line
)
841 if (prefs
.view_mode
== WIDE
) {
842 search_len
= MAX_WIDTH
;
844 else { /* prefs.view_mode == NARROW */
845 search_len
= crop_at_width(cur_line
) - cur_line
;
848 size
= BUFFER_OOB(cur_line
+search_len
) ? buffer_end
-cur_line
: search_len
;
850 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
)) {
851 /* Need to scan ahead and possibly increase search_len and size,
852 or possibly set next_line at second hard return in a row. */
855 j_next
=j
=k
=width
=spaces
=newlines
=0;
857 const unsigned char *p
, *oldp
;
862 if (BUFFER_OOB(cur_line
+j
))
864 if (line_is_full(k
, width
)) {
865 size
= search_len
= j_prev
;
869 oldp
= p
= &cur_line
[j
];
871 j_next
= j
+ (p
- oldp
);
875 if (prefs
.line_mode
== REFLOW
) {
878 next_line
= cur_line
+ size
;
879 return (unsigned char*) next_line
;
881 if (j
==0) /* i=1 is intentional */
882 for (i
=0; i
<par_indent_spaces
; i
++)
883 advance_conters(' ', &k
, &width
);
885 if (!first_chars
) spaces
++;
891 next_line
= cur_line
+ size
- spaces
;
892 if (next_line
!= cur_line
)
893 return (unsigned char*) next_line
;
899 if (BUFFER_OOB(cur_line
+size
) || size
> 2*search_len
)
902 spaces
= first_chars
? 0:1;
906 if (prefs
.line_mode
==JOIN
|| newlines
>0) {
909 advance_conters(' ', &k
, &width
);
910 if (line_is_full(k
, width
)) {
911 size
= search_len
= j
;
917 /* REFLOW, multiple spaces between words: count only
918 * one. If more are needed, they will be added
922 advance_conters(' ', &k
, &width
);
923 if (line_is_full(k
, width
)) {
924 size
= search_len
= j
;
929 advance_conters(ch
, &k
, &width
);
935 /* find first hard return */
936 next_line
= find_first_feed(cur_line
, size
);
939 if (next_line
== NULL
)
940 if (size
== search_len
) {
941 if (prefs
.word_mode
== WRAP
) /* Find last space */
942 next_line
= find_last_space(cur_line
, size
);
944 if (next_line
== NULL
) {
945 next_line
= crop_at_width(cur_line
);
948 if (prefs
.word_mode
== WRAP
) {
949 for (i
=0;i
<WRAP_TRIM
;i
++) {
950 if (!(isspace(next_line
[0]) && !BUFFER_OOB(next_line
)))
958 if (prefs
.line_mode
== EXPAND
)
959 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
960 if (next_line
[0] == 0)
961 if (next_line
!= cur_line
)
962 return (unsigned char*) next_line
;
964 /* If next_line is pointing to a zero, increment it; i.e.,
965 leave the terminator at the end of cur_line. If pointing
966 to a hyphen, increment only if there is room to display
967 the hyphen on current line (won't apply in WIDE mode,
968 since it's guarenteed there won't be room). */
969 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
970 if (next_line
[0] == 0)/* ||
971 (next_line[0] == '-' && next_line-cur_line < draw_columns)) */
974 if (BUFFER_OOB(next_line
))
976 if (BUFFER_EOF() && next_line
!= cur_line
)
977 return (unsigned char*) next_line
;
984 return (unsigned char*) next_line
;
987 static unsigned char* find_prev_line(const unsigned char* cur_line
)
989 const unsigned char *prev_line
= NULL
;
990 const unsigned char *p
;
992 if BUFFER_OOB(cur_line
)
995 /* To wrap consistently at the same places, we must
996 start with a known hard return, then work downwards.
997 We can either search backwards for a hard return,
998 or simply start wrapping downwards from top of buffer.
999 If current line is not near top of buffer, this is
1000 a file with long lines (paragraphs). We would need to
1001 read earlier sectors before we could decide how to
1002 properly wrap the lines above the current line, but
1003 it probably is not worth the disk access. Instead,
1004 start with top of buffer and wrap down from there.
1005 This may result in some lines wrapping at different
1006 points from where they wrap when scrolling down.
1007 If buffer is at top of file, start at top of buffer. */
1009 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
))
1010 prev_line
= p
= NULL
;
1012 prev_line
= p
= find_last_feed(buffer
, cur_line
-buffer
-1);
1013 /* Null means no line feeds in buffer above current line. */
1015 if (prev_line
== NULL
)
1016 if (BUFFER_BOF() || cur_line
- buffer
> READ_PREV_ZONE
)
1017 prev_line
= p
= buffer
;
1018 /* (else return NULL and read previous block) */
1020 /* Wrap downwards until too far, then use the one before. */
1021 while (p
!= NULL
&& p
< cur_line
) {
1023 p
= find_next_line(prev_line
, NULL
);
1026 if (BUFFER_OOB(prev_line
))
1029 return (unsigned char*) prev_line
;
1032 static void check_bom(void)
1034 unsigned char bom
[BOM_SIZE
];
1035 off_t orig
= rb
->lseek(fd
, 0, SEEK_CUR
);
1039 rb
->lseek(fd
, 0, SEEK_SET
);
1041 if (rb
->read(fd
, bom
, BOM_SIZE
) == BOM_SIZE
)
1042 is_bom
= !memcmp(bom
, BOM
, BOM_SIZE
);
1044 rb
->lseek(fd
, orig
, SEEK_SET
);
1047 static void fill_buffer(long pos
, unsigned char* buf
, unsigned size
)
1049 /* Read from file and preprocess the data */
1050 /* To minimize disk access, always read on sector boundaries */
1051 unsigned numread
, i
;
1052 bool found_CR
= false;
1053 off_t offset
= rb
->lseek(fd
, pos
, SEEK_SET
);
1055 if (offset
== 0 && prefs
.encoding
== UTF_8
&& is_bom
)
1056 rb
->lseek(fd
, BOM_SIZE
, SEEK_SET
);
1058 numread
= rb
->read(fd
, buf
, size
- 1);
1060 rb
->button_clear_queue(); /* clear button queue */
1062 for(i
= 0; i
< numread
; i
++) {
1079 case 0: /* No break between case 0 and default, intentionally */
1092 static int viewer_find_bookmark(int page
, int line
)
1096 for (i
= 0; i
< bookmark_count
; i
++)
1098 if (bookmarks
[i
].page
== page
&& bookmarks
[i
].line
== line
)
1104 static int read_and_synch(int direction
)
1106 /* Read next (or prev) block, and reposition global pointers. */
1107 /* direction: 1 for down (i.e., further into file), -1 for up */
1108 int move_size
, move_vector
, offset
;
1109 unsigned char *fill_buf
;
1111 if (direction
== -1) /* up */ {
1112 move_size
= SMALL_BLOCK_SIZE
;
1114 fill_buf
= TOP_SECTOR
;
1115 rb
->memcpy(BOTTOM_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
1116 rb
->memcpy(MID_SECTOR
, TOP_SECTOR
, SMALL_BLOCK_SIZE
);
1119 if (prefs
.view_mode
== WIDE
) {
1120 /* WIDE mode needs more buffer so we have to read smaller blocks */
1121 move_size
= SMALL_BLOCK_SIZE
;
1122 offset
= LARGE_BLOCK_SIZE
;
1123 fill_buf
= BOTTOM_SECTOR
;
1124 rb
->memcpy(TOP_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
1125 rb
->memcpy(MID_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
1128 move_size
= LARGE_BLOCK_SIZE
;
1129 offset
= SMALL_BLOCK_SIZE
;
1130 fill_buf
= MID_SECTOR
;
1131 rb
->memcpy(TOP_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
1134 move_vector
= direction
* move_size
;
1135 screen_top_ptr
-= move_vector
;
1136 file_pos
+= move_vector
;
1137 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1138 fill_buffer(file_pos
+ offset
, fill_buf
, move_size
);
1142 static void get_next_line_position(unsigned char **line_begin
,
1143 unsigned char **line_end
,
1148 *line_begin
= *line_end
;
1149 *line_end
= find_next_line(*line_begin
, is_short
);
1151 if (*line_end
== NULL
&& !BUFFER_EOF())
1153 resynch_move
= read_and_synch(1); /* Read block & move ptrs */
1154 *line_begin
-= resynch_move
;
1155 if (next_line_ptr
> buffer
)
1156 next_line_ptr
-= resynch_move
;
1158 *line_end
= find_next_line(*line_begin
, is_short
);
1162 static void increment_current_line(void)
1164 if (cline
< display_lines
)
1166 else if (cpage
< MAX_PAGE
)
1173 static void decrement_current_line(void)
1180 cline
= display_lines
;
1184 static void viewer_scroll_up(void)
1188 p
= find_prev_line(screen_top_ptr
);
1189 if (p
== NULL
&& !BUFFER_BOF()) {
1191 p
= find_prev_line(screen_top_ptr
);
1196 decrement_current_line();
1199 static void viewer_scroll_down(bool autoscroll
)
1204 if (next_line_ptr
!= NULL
)
1205 screen_top_ptr
= next_line_ptr
;
1207 if (prefs
.scroll_mode
== LINE
|| autoscroll
)
1208 increment_current_line();
1211 static void viewer_scroll_to_top_line(void)
1215 for (line
= cline
; line
> 1; line
--)
1219 #ifdef HAVE_LCD_BITMAP
1220 static void viewer_scrollbar(void) {
1221 int items
, min_shown
, max_shown
, sb_begin_y
, sb_height
;
1223 items
= (int) file_size
; /* (SH1 int is same as long) */
1224 min_shown
= (int) file_pos
+ (screen_top_ptr
- buffer
);
1226 if (next_screen_ptr
== NULL
)
1229 max_shown
= min_shown
+ (next_screen_ptr
- screen_top_ptr
);
1231 sb_begin_y
= header_height
;
1232 sb_height
= LCD_HEIGHT
- header_height
- footer_height
;
1234 rb
->gui_scrollbar_draw(rb
->screens
[SCREEN_MAIN
],0, sb_begin_y
,
1235 SCROLLBAR_WIDTH
-1, sb_height
,
1236 items
, min_shown
, max_shown
, VERTICAL
);
1240 #ifdef HAVE_LCD_BITMAP
1241 static void viewer_show_header(void)
1243 if (prefs
.header_mode
== HD_SBAR
|| prefs
.header_mode
== HD_BOTH
)
1244 rb
->gui_syncstatusbar_draw(rb
->statusbars
, true);
1246 if (prefs
.header_mode
== HD_PATH
|| prefs
.header_mode
== HD_BOTH
)
1247 rb
->lcd_putsxy(0, header_height
- pf
->height
, file_name
);
1250 static void viewer_show_footer(void)
1252 if (prefs
.footer_mode
== FT_SBAR
|| prefs
.footer_mode
== FT_BOTH
)
1253 rb
->gui_syncstatusbar_draw(rb
->statusbars
, true);
1255 if (prefs
.footer_mode
== FT_PAGE
|| prefs
.footer_mode
== FT_BOTH
)
1257 unsigned char buf
[12];
1260 rb
->snprintf(buf
, sizeof(buf
), "%d", cpage
);
1262 rb
->snprintf(buf
, sizeof(buf
), "%d - %d", cpage
, cpage
+1);
1264 rb
->lcd_putsxy(0, LCD_HEIGHT
- footer_height
, buf
);
1269 /* We draw a diacritic char over a non-diacritic one. Therefore, such chars are
1270 * not considered to occupy space, therefore buffers might have more than
1271 * max_columns characters. The DIACRITIC_FACTOR is the max ratio between all
1272 * characters and non-diacritic characters in the buffer
1274 #define DIACRITIC_FACTOR 2
1276 static void viewer_draw(int col
)
1278 int i
, j
, k
, line_len
, line_width
, spaces
, left_col
=0;
1279 int width
, extra_spaces
, indent_spaces
, spaces_per_word
, spaces_width
;
1280 bool multiple_spacing
, line_is_short
;
1282 unsigned char *str
, *oldstr
;
1283 unsigned char *line_begin
;
1284 unsigned char *line_end
;
1286 int max_chars
= max_columns
* DIACRITIC_FACTOR
;
1287 unsigned char scratch_buffer
[max_chars
+ 1];
1288 unsigned char utf8_buffer
[max_chars
* 4 + 1];
1289 unsigned char *endptr
;
1291 /* If col==-1 do all calculations but don't display */
1293 #ifdef HAVE_LCD_BITMAP
1294 left_col
= prefs
.need_scrollbar
? SCROLLBAR_WIDTH
:0;
1298 rb
->lcd_clear_display();
1301 line_begin
= line_end
= screen_top_ptr
;
1303 for (i
= 0; i
< display_lines
; i
++) {
1304 if (BUFFER_OOB(line_end
))
1307 break; /* Happens after display last line at BUFFER_EOF() */
1309 if (lpage
== 0 && cline
== 1)
1312 last_screen_top_ptr
= screen_top_ptr
;
1313 last_file_pos
= file_pos
;
1317 get_next_line_position(&line_begin
, &line_end
, &line_is_short
);
1318 if (line_end
== NULL
)
1320 if (BUFFER_OOB(line_begin
))
1322 line_end
= buffer_end
+ 1;
1325 line_len
= line_end
- line_begin
;
1327 /* calculate line_len */
1328 str
= oldstr
= line_begin
;
1330 while (str
< line_end
) {
1332 str
= crop_at_width(str
);
1340 /* width of un-displayed part of the line */
1341 line_width
= j
*draw_columns
;
1343 while (oldstr
< line_end
) {
1344 oldstr
= get_ucs(oldstr
, &ch
);
1345 /* add width of displayed part of the line */
1348 int dw
= glyph_width(ch
);
1350 /* avoid counting spaces at the end of the line */
1357 line_width
+= dw
+ spaces_width
;
1363 if (prefs
.line_mode
== JOIN
) {
1364 if (line_begin
[0] == 0) {
1366 if (prefs
.word_mode
== CHOP
)
1371 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
1382 scratch_buffer
[k
++] = ' ';
1387 scratch_buffer
[k
++] = ' ';
1388 if (k
== max_chars
- 1)
1391 scratch_buffer
[k
++] = c
;
1396 scratch_buffer
[k
] = 0;
1397 endptr
= decode2utf8(scratch_buffer
, utf8_buffer
, col
, draw_columns
);
1401 else if (prefs
.line_mode
== REFLOW
) {
1402 if (line_begin
[0] == 0) {
1404 if (prefs
.word_mode
== CHOP
)
1411 if (!line_is_short
) {
1412 multiple_spacing
= false;
1414 for (str
= line_begin
; str
< line_end
; ) {
1415 str
= get_ucs(str
, &ch
);
1419 if ((str
== line_begin
) && (prefs
.word_mode
==WRAP
))
1420 /* special case: indent the paragraph,
1421 * don't count spaces */
1422 indent_spaces
= par_indent_spaces
;
1423 else if (!multiple_spacing
)
1425 multiple_spacing
= true;
1428 multiple_spacing
= false;
1429 width
+= glyph_width(ch
);
1433 if (multiple_spacing
) spaces
--;
1436 /* total number of spaces to insert between words */
1437 extra_spaces
= (max_width
-width
)/glyph_width(' ')
1439 /* number of spaces between each word*/
1440 spaces_per_word
= extra_spaces
/ spaces
;
1441 /* number of words with n+1 spaces (to fill up) */
1442 extra_spaces
= extra_spaces
% spaces
;
1443 if (spaces_per_word
> 2) { /* too much spacing is awful */
1444 spaces_per_word
= 3;
1447 } else { /* this doesn't matter much... no spaces anyway */
1448 spaces_per_word
= extra_spaces
= 0;
1450 } else { /* end of a paragraph: don't fill line */
1451 spaces_per_word
= 1;
1455 multiple_spacing
= false;
1456 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
1464 if (j
==0 && prefs
.word_mode
==WRAP
) { /* indent paragraph */
1465 for (j
=0; j
<par_indent_spaces
; j
++)
1466 scratch_buffer
[k
++] = ' ';
1469 else if (!multiple_spacing
) {
1470 for (width
= spaces
<extra_spaces
? -1:0; width
< spaces_per_word
; width
++)
1471 scratch_buffer
[k
++] = ' ';
1474 multiple_spacing
= true;
1477 scratch_buffer
[k
++] = c
;
1478 multiple_spacing
= false;
1483 scratch_buffer
[k
] = 0;
1484 endptr
= decode2utf8(scratch_buffer
, utf8_buffer
, col
, draw_columns
);
1488 else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */
1489 if ((col
!= -1) && (line_width
> col
)) {
1490 str
= oldstr
= line_begin
;
1493 while( (width
<draw_columns
) && (oldstr
<line_end
) )
1495 oldstr
= get_ucs(oldstr
, &ch
);
1497 k
-= glyph_width(ch
);
1498 line_begin
= oldstr
;
1500 width
+= glyph_width(ch
);
1504 if(prefs
.view_mode
==WIDE
)
1505 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1506 prefs
.encoding
, oldstr
-line_begin
);
1508 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1509 prefs
.encoding
, line_end
-line_begin
);
1514 /* display on screen the displayed part of the line */
1515 if (col
!= -1 && line_width
> col
)
1517 int dpage
= (cline
+i
<= display_lines
)?cpage
:cpage
+1;
1518 int dline
= cline
+i
- ((cline
+i
<= display_lines
)?0:display_lines
);
1519 bool bflag
= (viewer_find_bookmark(dpage
, dline
) >= 0);
1520 #ifdef HAVE_LCD_BITMAP
1521 int dy
= i
* pf
->height
+ header_height
;
1522 int dx
= (prefs
.alignment
== LEFT
) ? left_col
: LCD_WIDTH
- line_width
;
1525 #ifdef HAVE_LCD_BITMAP
1527 rb
->lcd_set_drawmode(DRMODE_BG
|DRMODE_FG
);
1528 rb
->lcd_fillrect(left_col
, dy
, LCD_WIDTH
- left_col
, pf
->height
);
1529 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
1531 rb
->lcd_putsxy(dx
, dy
, utf8_buffer
);
1532 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1535 rb
->lcd_puts(left_col
, i
, BOOKMARK_ICON
);
1537 rb
->lcd_puts(left_col
+1, i
, utf8_buffer
);
1540 if (line_width
> max_line_len
)
1541 max_line_len
= line_width
;
1544 next_line_ptr
= line_end
;
1546 next_screen_ptr
= line_end
;
1547 if (BUFFER_OOB(next_screen_ptr
))
1548 next_screen_ptr
= NULL
;
1550 #ifdef HAVE_LCD_BITMAP
1551 next_screen_to_draw_ptr
= prefs
.page_mode
==OVERLAP
? line_begin
: next_screen_ptr
;
1553 if (prefs
.need_scrollbar
)
1556 next_screen_to_draw_ptr
= next_screen_ptr
;
1559 #ifdef HAVE_LCD_BITMAP
1561 viewer_show_header();
1564 viewer_show_footer();
1571 static void viewer_top(void)
1573 /* Read top of file into buffer
1574 and point screen pointer to top */
1577 rb
->splash(0, "Loading...");
1580 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1581 fill_buffer(0, buffer
, buffer_size
);
1584 screen_top_ptr
= buffer
;
1589 static void viewer_bottom(void)
1591 unsigned char *line_begin
;
1592 unsigned char *line_end
;
1594 rb
->splash(0, "Loading...");
1596 if (last_screen_top_ptr
)
1600 screen_top_ptr
= last_screen_top_ptr
;
1601 file_pos
= last_file_pos
;
1602 fill_buffer(file_pos
, buffer
, buffer_size
);
1603 buffer_end
= BUFFER_END();
1607 line_end
= screen_top_ptr
;
1609 while (!BUFFER_EOF() || !BUFFER_OOB(line_end
))
1611 get_next_line_position(&line_begin
, &line_end
, NULL
);
1612 if (line_end
== NULL
)
1615 increment_current_line();
1617 screen_top_ptr
= line_end
;
1621 last_screen_top_ptr
= screen_top_ptr
;
1622 last_file_pos
= file_pos
;
1623 buffer_end
= BUFFER_END();
1626 #ifdef HAVE_LCD_BITMAP
1627 static void init_need_scrollbar(void) {
1628 /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
1629 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
1631 prefs
.need_scrollbar
= NEED_SCROLLBAR();
1632 draw_columns
= prefs
.need_scrollbar
? display_columns
-SCROLLBAR_WIDTH
: display_columns
;
1633 par_indent_spaces
= draw_columns
/(5*glyph_width(' '));
1637 static void init_header_and_footer(void)
1641 if (rb
->global_settings
->statusbar
== STATUSBAR_TOP
)
1643 if (prefs
.header_mode
== HD_SBAR
|| prefs
.header_mode
== HD_BOTH
)
1644 header_height
= STATUSBAR_HEIGHT
;
1646 if (prefs
.footer_mode
== FT_SBAR
)
1647 prefs
.footer_mode
= FT_NONE
;
1648 else if (prefs
.footer_mode
== FT_BOTH
)
1649 prefs
.footer_mode
= FT_PAGE
;
1651 else if (rb
->global_settings
->statusbar
== STATUSBAR_BOTTOM
)
1653 if (prefs
.footer_mode
== FT_SBAR
|| prefs
.footer_mode
== FT_BOTH
)
1654 footer_height
= STATUSBAR_HEIGHT
;
1656 if (prefs
.header_mode
== HD_SBAR
)
1657 prefs
.header_mode
= HD_NONE
;
1658 else if (prefs
.header_mode
== HD_BOTH
)
1659 prefs
.header_mode
= HD_PATH
;
1661 else /* STATUSBAR_OFF || STATUSBAR_CUSTOM */
1663 if (prefs
.header_mode
== HD_SBAR
)
1664 prefs
.header_mode
= HD_NONE
;
1665 else if (prefs
.header_mode
== HD_BOTH
)
1666 prefs
.header_mode
= HD_PATH
;
1668 if (prefs
.footer_mode
== FT_SBAR
)
1669 prefs
.footer_mode
= FT_NONE
;
1670 else if (prefs
.footer_mode
== FT_BOTH
)
1671 prefs
.footer_mode
= FT_PAGE
;
1674 if (prefs
.header_mode
== HD_NONE
|| prefs
.header_mode
== HD_PATH
||
1675 prefs
.footer_mode
== FT_NONE
|| prefs
.footer_mode
== FT_PAGE
)
1676 rb
->gui_syncstatusbar_draw(rb
->statusbars
, false);
1678 if (prefs
.header_mode
== HD_PATH
|| prefs
.header_mode
== HD_BOTH
)
1679 header_height
+= pf
->height
;
1680 if (prefs
.footer_mode
== FT_PAGE
|| prefs
.footer_mode
== FT_BOTH
)
1681 footer_height
+= pf
->height
;
1683 display_lines
= (LCD_HEIGHT
- header_height
- footer_height
) / pf
->height
;
1687 last_screen_top_ptr
= NULL
;
1690 static bool change_font(unsigned char *font
)
1692 unsigned char buf
[MAX_PATH
];
1694 if (font
== NULL
|| *font
== '\0')
1697 rb
->snprintf(buf
, MAX_PATH
, "%s/%s.fnt", FONT_DIR
, font
);
1698 if (rb
->font_load(NULL
, buf
) < 0) {
1699 rb
->splash(HZ
/2, "Font load failed.");
1707 static bool viewer_init(void)
1709 #ifdef HAVE_LCD_BITMAP
1710 /* initialize fonts */
1711 pf
= rb
->font_get(FONT_UI
);
1715 draw_columns
= display_columns
= LCD_WIDTH
;
1717 /* REAL fixed pitch :) all chars use up 1 cell */
1719 draw_columns
= display_columns
= 11;
1720 par_indent_spaces
= 2;
1723 fd
= rb
->open(file_name
, O_RDONLY
);
1727 /* Init mac_text value used in processing buffer */
1733 /* When a file is UTF-8 file with BOM, if prefs.encoding is UTF-8,
1734 * then file size decreases only BOM_SIZE.
1736 static void get_filesize(void)
1738 file_size
= rb
->filesize(fd
);
1739 if (file_size
== -1)
1742 if (prefs
.encoding
== UTF_8
&& is_bom
)
1743 file_size
-= BOM_SIZE
;
1746 static int bm_comp(const void *a
, const void *b
)
1748 struct bookmark_info
*pa
;
1749 struct bookmark_info
*pb
;
1751 pa
= (struct bookmark_info
*)a
;
1752 pb
= (struct bookmark_info
*)b
;
1754 if (pa
->page
!= pb
->page
)
1755 return pa
->page
- pb
->page
;
1757 return pa
->line
- pb
->line
;
1760 static void viewer_add_bookmark(void)
1762 if (bookmark_count
>= MAX_BOOKMARKS
-1)
1765 bookmarks
[bookmark_count
].file_position
1766 = file_pos
+ screen_top_ptr
- buffer
;
1767 bookmarks
[bookmark_count
].page
= cpage
;
1768 bookmarks
[bookmark_count
].line
= cline
;
1769 bookmarks
[bookmark_count
].flag
= BOOKMARK_USER
;
1773 static int viewer_add_last_read_bookmark(void)
1777 i
= viewer_find_bookmark(cpage
, cline
);
1779 bookmarks
[i
].flag
|= BOOKMARK_LAST
;
1782 viewer_add_bookmark();
1783 i
= bookmark_count
-1;
1784 bookmarks
[i
].flag
= BOOKMARK_LAST
;
1789 static void viewer_remove_bookmark(int i
)
1793 if (i
< 0 || i
>= bookmark_count
)
1796 for (j
= i
+1; j
< bookmark_count
; j
++)
1797 rb
->memcpy(&bookmarks
[j
-1], &bookmarks
[j
],
1798 sizeof(struct bookmark_info
));
1803 static void viewer_remove_last_read_bookmark(void)
1807 for (i
= 0; i
< bookmark_count
; i
++)
1809 if (bookmarks
[i
].flag
& BOOKMARK_LAST
)
1811 if (bookmarks
[i
].flag
== BOOKMARK_LAST
)
1813 for (j
= i
+1; j
< bookmark_count
; j
++)
1814 rb
->memcpy(&bookmarks
[j
-1], &bookmarks
[j
],
1815 sizeof(struct bookmark_info
));
1820 bookmarks
[i
].flag
= BOOKMARK_USER
;
1826 static int viewer_get_last_read_bookmark(void)
1830 for (i
= 0; i
< bookmark_count
; i
++)
1832 if (bookmarks
[i
].flag
& BOOKMARK_LAST
)
1838 static void viewer_select_bookmark(int initval
)
1847 struct opt_items items
[bookmark_count
];
1848 unsigned char names
[bookmark_count
][38];
1850 if (initval
>= 0 && initval
< bookmark_count
)
1852 ipage
= bookmarks
[initval
].page
;
1853 iline
= bookmarks
[initval
].line
;
1856 rb
->qsort(bookmarks
, bookmark_count
, sizeof(struct bookmark_info
),
1859 for (i
= 0; i
< bookmark_count
; i
++)
1861 rb
->snprintf(names
[i
], sizeof(names
[0]),
1862 #if CONFIG_KEYPAD != PLAYER_PAD
1863 "%sPage: %d Line: %d",
1867 (bookmarks
[i
].flag
&BOOKMARK_LAST
)? "*":" ",
1870 items
[i
].string
= names
[i
];
1871 items
[i
].voice_id
= -1;
1872 if (selected
< 0 && bookmarks
[i
].page
== ipage
&& bookmarks
[i
].line
== iline
)
1876 rb
->set_option("Select bookmark", &selected
, INT
, items
,
1877 sizeof(items
) / sizeof(items
[0]), NULL
);
1879 if (selected
< 0 || selected
>= bookmark_count
)
1881 if (initval
< 0 || (selected
= viewer_get_last_read_bookmark()) < 0)
1884 rb
->splash(HZ
, "Start the first page.");
1886 screen_top_ptr
= buffer
;
1889 buffer_end
= BUFFER_END();
1894 screen_pos
= bookmarks
[selected
].file_position
;
1895 screen_top
= screen_pos
% buffer_size
;
1896 file_pos
= screen_pos
- screen_top
;
1897 screen_top_ptr
= buffer
+ screen_top
;
1898 cpage
= bookmarks
[selected
].page
;
1899 cline
= bookmarks
[selected
].line
;
1900 buffer_end
= BUFFER_END();
1903 static void viewer_default_preferences(void)
1905 prefs
.word_mode
= WRAP
;
1906 prefs
.line_mode
= NORMAL
;
1907 prefs
.view_mode
= NARROW
;
1908 prefs
.alignment
= LEFT
;
1909 prefs
.scroll_mode
= PAGE
;
1910 prefs
.page_mode
= NO_OVERLAP
;
1911 prefs
.scrollbar_mode
= SB_OFF
;
1912 rb
->memset(prefs
.font
, 0, MAX_PATH
);
1913 #ifdef HAVE_LCD_BITMAP
1914 prefs
.header_mode
= HD_BOTH
;
1915 prefs
.footer_mode
= FT_BOTH
;
1916 rb
->snprintf(prefs
.font
, MAX_PATH
, "%s", rb
->global_settings
->font_file
);
1918 prefs
.header_mode
= HD_NONE
;
1919 prefs
.footer_mode
= FT_NONE
;
1921 prefs
.autoscroll_speed
= 1;
1922 /* Set codepage to system default */
1923 prefs
.encoding
= rb
->global_settings
->default_codepage
;
1926 static bool viewer_read_preferences(int pfd
, int version
, struct preferences
*prf
)
1928 unsigned char buf
[PREFERENCES_SIZE
];
1929 unsigned char *p
= buf
;
1930 int read_size
= PREFERENCES_SIZE
;
1935 if (rb
->read(pfd
, buf
, read_size
) != read_size
)
1938 prf
->word_mode
= *p
++;
1939 prf
->line_mode
= *p
++;
1940 prf
->view_mode
= *p
++;
1942 prf
->alignment
= *p
++;
1944 prf
->alignment
= LEFT
;
1945 prf
->encoding
= *p
++;
1946 prf
->scrollbar_mode
= *p
++;
1947 prf
->need_scrollbar
= *p
++;
1948 prf
->page_mode
= *p
++;
1949 prf
->header_mode
= *p
++;
1950 prf
->footer_mode
= *p
++;
1951 prf
->scroll_mode
= *p
++;
1952 prf
->autoscroll_speed
= *p
++;
1953 rb
->memcpy(prf
->font
, p
, MAX_PATH
);
1957 static bool viewer_write_preferences(int pfd
, const struct preferences
*prf
)
1959 unsigned char buf
[PREFERENCES_SIZE
];
1960 unsigned char *p
= buf
;
1962 *p
++ = prf
->word_mode
;
1963 *p
++ = prf
->line_mode
;
1964 *p
++ = prf
->view_mode
;
1965 *p
++ = prf
->alignment
;
1966 *p
++ = prf
->encoding
;
1967 *p
++ = prf
->scrollbar_mode
;
1968 *p
++ = prf
->need_scrollbar
;
1969 *p
++ = prf
->page_mode
;
1970 *p
++ = prf
->header_mode
;
1971 *p
++ = prf
->footer_mode
;
1972 *p
++ = prf
->scroll_mode
;
1973 *p
++ = prf
->autoscroll_speed
;
1974 rb
->memcpy(p
, prf
->font
, MAX_PATH
);
1976 return (rb
->write(pfd
, buf
, sizeof(buf
)) == sizeof(buf
));
1979 static bool viewer_read_bookmark_info(int bfd
, struct bookmark_info
*b
)
1981 unsigned char buf
[BOOKMARK_SIZE
];
1983 if (rb
->read(bfd
, buf
, sizeof(buf
)) != sizeof(buf
))
1986 b
->file_position
= (buf
[0] << 24)|(buf
[1] << 16)|(buf
[2] << 8)|buf
[3];
1987 b
->page
= (buf
[4] << 8)|buf
[5];
1994 static bool viewer_read_bookmark_infos(int bfd
)
1999 if (rb
->read(bfd
, &c
, 1) != 1)
2006 if (bookmark_count
> MAX_BOOKMARKS
)
2007 bookmark_count
= MAX_BOOKMARKS
;
2009 for (i
= 0; i
< bookmark_count
; i
++)
2011 if (!viewer_read_bookmark_info(bfd
, &bookmarks
[i
]))
2020 static bool viewer_write_bookmark_info(int bfd
, struct bookmark_info
*b
)
2022 unsigned char buf
[BOOKMARK_SIZE
];
2023 unsigned char *p
= buf
;
2026 ul
= b
->file_position
;
2039 return (rb
->write(bfd
, buf
, sizeof(buf
)) == sizeof(buf
));
2042 static bool viewer_write_bookmark_infos(int bfd
)
2044 unsigned char c
= bookmark_count
;
2047 if (rb
->write(bfd
, &c
, 1) != 1)
2050 for (i
= 0; i
< bookmark_count
; i
++)
2052 if (!viewer_write_bookmark_info(bfd
, &bookmarks
[i
]))
2059 static bool viewer_load_global_settings(void)
2061 unsigned buf
[GLOBAL_SETTINGS_H_SIZE
];
2062 int sfd
= rb
->open(GLOBAL_SETTINGS_FILE
, O_RDONLY
);
2069 if ((rb
->read(sfd
, buf
, GLOBAL_SETTINGS_H_SIZE
) == GLOBAL_SETTINGS_H_SIZE
) ||
2070 (rb
->memcmp(buf
, GLOBAL_SETTINGS_HEADER
, GLOBAL_SETTINGS_H_SIZE
- 1) == 0))
2072 version
= buf
[GLOBAL_SETTINGS_H_SIZE
- 1] - GLOBAL_SETTINGS_FIRST_VERSION
;
2073 res
= viewer_read_preferences(sfd
, version
, &prefs
);
2079 static bool viewer_save_global_settings(void)
2081 int sfd
= rb
->open(GLOBAL_SETTINGS_TMP_FILE
, O_WRONLY
|O_CREAT
|O_TRUNC
);
2082 unsigned char buf
[GLOBAL_SETTINGS_H_SIZE
];
2087 rb
->memcpy(buf
, GLOBAL_SETTINGS_HEADER
, GLOBAL_SETTINGS_H_SIZE
- 1);
2088 buf
[GLOBAL_SETTINGS_H_SIZE
- 1] = GLOBAL_SETTINGS_VERSION
;
2090 if (rb
->write(sfd
, buf
, GLOBAL_SETTINGS_H_SIZE
) != GLOBAL_SETTINGS_H_SIZE
||
2091 !viewer_write_preferences(sfd
, &prefs
))
2094 rb
->remove(GLOBAL_SETTINGS_TMP_FILE
);
2098 rb
->remove(GLOBAL_SETTINGS_FILE
);
2099 rb
->rename(GLOBAL_SETTINGS_TMP_FILE
, GLOBAL_SETTINGS_FILE
);
2103 static bool viewer_convert_settings(int sfd
, int dfd
, int old_ver
)
2105 struct preferences new_prefs
;
2108 unsigned char buf
[MAX_PATH
+ 2];
2111 rb
->read(sfd
, buf
, MAX_PATH
+ 2);
2112 rb
->write(dfd
, buf
, MAX_PATH
+ 2);
2114 settings_size
= (buf
[MAX_PATH
] << 8) | buf
[MAX_PATH
+ 1];
2116 old_pos
= rb
->lseek(sfd
, 0, SEEK_CUR
);
2117 new_pos
= rb
->lseek(dfd
, 0, SEEK_CUR
);
2120 * when the settings size != preferences size + bookmarks size,
2121 * settings data are considered to be old version.
2123 if (old_ver
> 0 && ((settings_size
- PREFERENCES_SIZE
) % 8) == 0)
2126 if (!viewer_read_preferences(sfd
, old_ver
, &new_prefs
))
2129 if (!viewer_write_preferences(dfd
, &new_prefs
))
2132 settings_size
-= (rb
->lseek(sfd
, 0, SEEK_CUR
) - old_pos
);
2134 if (settings_size
> 0)
2136 rb
->read(sfd
, buf
, settings_size
);
2137 rb
->write(dfd
, buf
, settings_size
);
2140 settings_size
= rb
->lseek(dfd
, 0, SEEK_CUR
) - new_pos
;
2141 buf
[0] = settings_size
>> 8;
2142 buf
[1] = settings_size
;
2143 rb
->lseek(dfd
, new_pos
- 2, SEEK_SET
);
2144 rb
->write(dfd
, buf
, 2);
2145 rb
->lseek(dfd
, settings_size
, SEEK_CUR
);
2149 static bool viewer_convert_settings_file(void)
2151 unsigned char buf
[SETTINGS_H_SIZE
+2];
2159 if ((sfd
= rb
->open(SETTINGS_FILE
, O_RDONLY
)) < 0)
2162 if ((tfd
= rb
->open(SETTINGS_TMP_FILE
, O_WRONLY
|O_CREAT
|O_TRUNC
)) < 0)
2168 rb
->read(sfd
, buf
, SETTINGS_H_SIZE
+ 2);
2170 version
= buf
[SETTINGS_H_SIZE
- 1] - SETTINGS_FIRST_VERSION
;
2171 fcount
= (buf
[SETTINGS_H_SIZE
] << 8) | buf
[SETTINGS_H_SIZE
+ 1];
2172 buf
[SETTINGS_H_SIZE
- 1] = SETTINGS_VERSION
;
2174 rb
->write(tfd
, buf
, SETTINGS_H_SIZE
+ 2);
2176 for (i
= 0; i
< fcount
; i
++)
2178 if (!viewer_convert_settings(sfd
, tfd
, version
))
2189 rb
->remove(SETTINGS_TMP_FILE
);
2192 rb
->remove(SETTINGS_FILE
);
2193 rb
->rename(SETTINGS_TMP_FILE
, SETTINGS_FILE
);
2198 static bool viewer_load_settings(void)
2200 unsigned char buf
[MAX_PATH
+2];
2201 unsigned int fcount
;
2208 sfd
= rb
->open(SETTINGS_FILE
, O_RDONLY
);
2212 if ((rb
->read(sfd
, buf
, SETTINGS_H_SIZE
+2) != SETTINGS_H_SIZE
+2) ||
2213 rb
->memcmp(buf
, SETTINGS_HEADER
, SETTINGS_H_SIZE
- 1))
2215 /* illegal setting file */
2218 if (rb
->file_exists(SETTINGS_FILE
))
2219 rb
->remove(SETTINGS_FILE
);
2224 if (buf
[SETTINGS_H_SIZE
- 1] != SETTINGS_VERSION
)
2227 if (!viewer_convert_settings_file())
2230 return viewer_load_settings();
2233 version
= buf
[SETTINGS_H_SIZE
- 1] - SETTINGS_FIRST_VERSION
;
2234 fcount
= (buf
[SETTINGS_H_SIZE
] << 8) | buf
[SETTINGS_H_SIZE
+1];
2235 for (i
= 0; i
< fcount
; i
++)
2237 if (rb
->read(sfd
, buf
, MAX_PATH
+2) != MAX_PATH
+2)
2240 size
= (buf
[MAX_PATH
] << 8) | buf
[MAX_PATH
+1];
2243 * when the settings size != preferences size + bookmarks size,
2244 * the settings file converts to the newer.
2246 if (version
> 0 && ((size
- PREFERENCES_SIZE
) % 8) == 0)
2249 if (!viewer_convert_settings_file())
2252 return viewer_load_settings();
2255 if (rb
->strcmp(buf
, file_name
))
2257 if (rb
->lseek(sfd
, size
, SEEK_CUR
) < 0)
2261 if (!viewer_read_preferences(sfd
, version
, &prefs
))
2264 res
= viewer_read_bookmark_infos(sfd
);
2273 /* load global settings */
2274 if (!viewer_load_global_settings())
2275 viewer_default_preferences();
2278 screen_top_ptr
= buffer
;
2284 rb
->memcpy(&old_prefs
, &prefs
, sizeof(struct preferences
));
2287 if (bookmark_count
> 1)
2288 viewer_select_bookmark(-1);
2289 else if (bookmark_count
== 1)
2294 screen_pos
= bookmarks
[0].file_position
;
2295 screen_top
= screen_pos
% buffer_size
;
2296 file_pos
= screen_pos
- screen_top
;
2297 screen_top_ptr
= buffer
+ screen_top
;
2298 cpage
= bookmarks
[0].page
;
2299 cline
= bookmarks
[0].line
;
2302 viewer_remove_last_read_bookmark();
2307 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
2309 if (BUFFER_OOB(screen_top_ptr
))
2310 screen_top_ptr
= buffer
;
2312 fill_buffer(file_pos
, buffer
, buffer_size
);
2313 if (prefs
.scroll_mode
== PAGE
&& cline
> 1)
2314 viewer_scroll_to_top_line();
2316 /* remember the current position */
2317 start_position
= file_pos
+ screen_top_ptr
- buffer
;
2319 #ifdef HAVE_LCD_BITMAP
2320 /* load prefs font if it is different than the global settings font */
2321 if (rb
->strcmp(prefs
.font
, rb
->global_settings
->font_file
)) {
2322 if (!change_font(prefs
.font
)) {
2323 /* fallback by resetting prefs font to the global settings font */
2324 rb
->memset(prefs
.font
, 0, MAX_PATH
);
2325 rb
->snprintf(prefs
.font
, MAX_PATH
, "%s",
2326 rb
->global_settings
->font_file
);
2328 if (!change_font(prefs
.font
))
2333 init_need_scrollbar();
2334 init_header_and_footer();
2340 static bool copy_bookmark_file(int sfd
, int dfd
, off_t start
, off_t size
)
2344 if (rb
->lseek(sfd
, start
, SEEK_SET
) < 0)
2349 if (size
> buffer_size
)
2350 rsize
= buffer_size
;
2355 if (rb
->read(sfd
, buffer
, rsize
) != rsize
||
2356 rb
->write(dfd
, buffer
, rsize
) != rsize
)
2362 static bool viewer_save_settings(void)
2364 unsigned char buf
[MAX_PATH
+2];
2365 unsigned int fcount
= 0;
2370 off_t first_copy_size
= 0;
2371 off_t second_copy_start_pos
= 0;
2374 /* add reading page to bookmarks */
2375 idx
= viewer_find_bookmark(cpage
, cline
);
2377 bookmarks
[idx
].flag
|= BOOKMARK_LAST
;
2380 viewer_add_bookmark();
2381 bookmarks
[bookmark_count
-1].flag
= BOOKMARK_LAST
;
2384 tfd
= rb
->open(SETTINGS_TMP_FILE
, O_WRONLY
|O_CREAT
|O_TRUNC
);
2388 ofd
= rb
->open(SETTINGS_FILE
, O_RDWR
);
2391 if ((rb
->read(ofd
, buf
, SETTINGS_H_SIZE
+2) != SETTINGS_H_SIZE
+2) ||
2392 rb
->memcmp(buf
, SETTINGS_HEADER
, SETTINGS_H_SIZE
- 1))
2398 if (buf
[SETTINGS_H_SIZE
- 1] != SETTINGS_VERSION
)
2401 if (!viewer_convert_settings_file())
2404 viewer_save_settings();
2407 fcount
= (buf
[SETTINGS_H_SIZE
] << 8) | buf
[SETTINGS_H_SIZE
+1];
2409 for (i
= 0; i
< fcount
; i
++)
2411 if (rb
->read(ofd
, buf
, MAX_PATH
+2) != MAX_PATH
+2)
2416 size
= (buf
[MAX_PATH
] << 8) | buf
[MAX_PATH
+1];
2417 if (rb
->strcmp(buf
, file_name
))
2419 if (rb
->lseek(ofd
, size
, SEEK_CUR
) < 0)
2427 first_copy_size
= rb
->lseek(ofd
, 0, SEEK_CUR
);
2428 if (first_copy_size
< 0)
2433 second_copy_start_pos
= first_copy_size
+ size
;
2434 first_copy_size
-= MAX_PATH
+2;
2439 if (first_copy_size
== 0)
2440 first_copy_size
= rb
->filesize(ofd
);
2442 if (!copy_bookmark_file(ofd
, tfd
, 0, first_copy_size
))
2447 if (second_copy_start_pos
> 0)
2449 if (!copy_bookmark_file(ofd
, tfd
, second_copy_start_pos
,
2450 rb
->filesize(ofd
) - second_copy_start_pos
))
2460 rb
->memcpy(buf
, SETTINGS_HEADER
, SETTINGS_H_SIZE
- 1);
2461 buf
[SETTINGS_H_SIZE
-1] = SETTINGS_VERSION
;
2462 buf
[SETTINGS_H_SIZE
] = 0;
2463 buf
[SETTINGS_H_SIZE
+1] = 0;
2464 if (rb
->write(tfd
, buf
, SETTINGS_H_SIZE
+2) != SETTINGS_H_SIZE
+2)
2468 /* copy to current read file's bookmarks */
2469 rb
->memset(buf
, 0, MAX_PATH
);
2470 rb
->snprintf(buf
, MAX_PATH
, "%s", file_name
);
2472 size
= PREFERENCES_SIZE
+ bookmark_count
* BOOKMARK_SIZE
+ 1;
2473 buf
[MAX_PATH
] = size
>> 8;
2474 buf
[MAX_PATH
+1] = size
;
2476 if (rb
->write(tfd
, buf
, MAX_PATH
+2) != MAX_PATH
+2)
2479 if (!viewer_write_preferences(tfd
, &prefs
))
2482 if (!viewer_write_bookmark_infos(tfd
))
2485 if (rb
->lseek(tfd
, SETTINGS_H_SIZE
, SEEK_SET
) < 0)
2489 buf
[0] = fcount
>> 8;
2492 if (rb
->write(tfd
, buf
, 2) != 2)
2497 rb
->remove(SETTINGS_FILE
);
2498 rb
->rename(SETTINGS_TMP_FILE
, SETTINGS_FILE
);
2504 rb
->remove(SETTINGS_TMP_FILE
);
2508 static void viewer_exit(void *parameter
)
2512 /* save preference and bookmarks */
2513 if (!viewer_save_settings())
2514 rb
->splash(HZ
, "Can't save preference and bookmarks.");
2517 #ifdef HAVE_LCD_BITMAP
2518 if (rb
->strcmp(prefs
.font
, rb
->global_settings
->font_file
))
2519 change_font(rb
->global_settings
->font_file
);
2523 static void calc_page(void)
2526 unsigned char *line_begin
;
2527 unsigned char *line_end
;
2529 unsigned char *sstp
;
2531 rb
->splash(0, "Calculating page/line number...");
2533 /* add reading page to bookmarks */
2534 viewer_add_last_read_bookmark();
2536 rb
->qsort(bookmarks
, bookmark_count
, sizeof(struct bookmark_info
),
2542 screen_top_ptr
= buffer
;
2543 buffer_end
= BUFFER_END();
2545 fill_buffer(file_pos
, buffer
, buffer_size
);
2546 line_end
= line_begin
= buffer
;
2548 for (i
= 0; i
< bookmark_count
; i
++)
2550 sfp
= bookmarks
[i
].file_position
;
2553 while ((line_begin
> sstp
|| sstp
>= line_end
) ||
2554 (file_pos
> sfp
|| sfp
>= file_pos
+ BUFFER_END() - buffer
))
2556 get_next_line_position(&line_begin
, &line_end
, NULL
);
2557 if (line_end
== NULL
)
2560 next_line_ptr
= line_end
;
2562 if (sstp
== buffer
&&
2563 file_pos
<= sfp
&& sfp
< file_pos
+ BUFFER_END() - buffer
)
2564 sstp
= sfp
- file_pos
+ buffer
;
2566 increment_current_line();
2569 decrement_current_line();
2570 bookmarks
[i
].page
= cpage
;
2571 bookmarks
[i
].line
= cline
;
2572 bookmarks
[i
].file_position
= file_pos
+ (line_begin
- buffer
);
2573 increment_current_line();
2576 /* remove reading page's bookmark */
2577 for (i
= 0; i
< bookmark_count
; i
++)
2579 if (bookmarks
[i
].flag
& BOOKMARK_LAST
)
2584 screen_pos
= bookmarks
[i
].file_position
;
2585 screen_top
= screen_pos
% buffer_size
;
2586 file_pos
= screen_pos
- screen_top
;
2587 screen_top_ptr
= buffer
+ screen_top
;
2589 cpage
= bookmarks
[i
].page
;
2590 cline
= bookmarks
[i
].line
;
2591 bookmarks
[i
].flag
^= BOOKMARK_LAST
;
2592 buffer_end
= BUFFER_END();
2594 fill_buffer(file_pos
, buffer
, buffer_size
);
2596 if (bookmarks
[i
].flag
== 0)
2597 viewer_remove_bookmark(i
);
2599 if (prefs
.scroll_mode
== PAGE
&& cline
> 1)
2600 viewer_scroll_to_top_line();
2606 static int col_limit(int col
)
2611 if (col
>= max_width
- draw_columns
)
2612 col
= max_width
- draw_columns
;
2617 /* settings helper functions */
2619 static bool encoding_setting(void)
2621 static struct opt_items names
[NUM_CODEPAGES
];
2624 enum codepages oldenc
= prefs
.encoding
;
2626 for (idx
= 0; idx
< NUM_CODEPAGES
; idx
++)
2628 names
[idx
].string
= rb
->get_codepage_name(idx
);
2629 names
[idx
].voice_id
= -1;
2632 res
= rb
->set_option("Encoding", &prefs
.encoding
, INT
, names
,
2633 sizeof(names
) / sizeof(names
[0]), NULL
);
2635 /* When prefs.encoding changes into UTF-8 or changes from UTF-8,
2636 * filesize (file_size) might change.
2637 * In addition, if prefs.encoding is UTF-8, then BOM does not read.
2639 if (oldenc
!= prefs
.encoding
&& (oldenc
== UTF_8
|| prefs
.encoding
== UTF_8
))
2643 fill_buffer(file_pos
, buffer
, buffer_size
);
2649 static bool word_wrap_setting(void)
2651 static const struct opt_items names
[] = {
2653 {"Off (Chop Words)", -1},
2656 return rb
->set_option("Word Wrap", &prefs
.word_mode
, INT
,
2660 static bool line_mode_setting(void)
2662 static const struct opt_items names
[] = {
2665 {"Expand Lines", -1},
2666 #ifdef HAVE_LCD_BITMAP
2667 {"Reflow Lines", -1},
2671 return rb
->set_option("Line Mode", &prefs
.line_mode
, INT
, names
,
2672 sizeof(names
) / sizeof(names
[0]), NULL
);
2675 static bool view_mode_setting(void)
2677 static const struct opt_items names
[] = {
2678 {"No (Narrow)", -1},
2682 ret
= rb
->set_option("Wide View", &prefs
.view_mode
, INT
,
2684 if (prefs
.view_mode
== NARROW
)
2690 static bool scroll_mode_setting(void)
2692 static const struct opt_items names
[] = {
2693 {"Scroll by Page", -1},
2694 {"Scroll by Line", -1},
2697 return rb
->set_option("Scroll Mode", &prefs
.scroll_mode
, INT
,
2701 #ifdef HAVE_LCD_BITMAP
2702 static bool page_mode_setting(void)
2704 static const struct opt_items names
[] = {
2709 return rb
->set_option("Overlap Pages", &prefs
.page_mode
, INT
,
2713 static bool scrollbar_setting(void)
2715 static const struct opt_items names
[] = {
2720 return rb
->set_option("Show Scrollbar", &prefs
.scrollbar_mode
, INT
,
2724 static bool header_setting(void)
2726 int len
= (rb
->global_settings
->statusbar
== STATUSBAR_TOP
)? 4 : 2;
2727 struct opt_items names
[len
];
2729 names
[0].string
= "None";
2730 names
[0].voice_id
= -1;
2731 names
[1].string
= "File path";
2732 names
[1].voice_id
= -1;
2734 if (rb
->global_settings
->statusbar
== STATUSBAR_TOP
)
2736 names
[2].string
= "Status bar";
2737 names
[2].voice_id
= -1;
2738 names
[3].string
= "Both";
2739 names
[3].voice_id
= -1;
2742 return rb
->set_option("Show Header", &prefs
.header_mode
, INT
,
2746 static bool footer_setting(void)
2748 int len
= (rb
->global_settings
->statusbar
== STATUSBAR_BOTTOM
)? 4 : 2;
2749 struct opt_items names
[len
];
2751 names
[0].string
= "None";
2752 names
[0].voice_id
= -1;
2753 names
[1].string
= "Page Num";
2754 names
[1].voice_id
= -1;
2756 if (rb
->global_settings
->statusbar
== STATUSBAR_BOTTOM
)
2758 names
[2].string
= "Status bar";
2759 names
[2].voice_id
= -1;
2760 names
[3].string
= "Both";
2761 names
[3].voice_id
= -1;
2764 return rb
->set_option("Show Footer", &prefs
.footer_mode
, INT
,
2768 static int font_comp(const void *a
, const void *b
)
2770 struct opt_items
*pa
;
2771 struct opt_items
*pb
;
2773 pa
= (struct opt_items
*)a
;
2774 pb
= (struct opt_items
*)b
;
2776 return rb
->strcmp(pa
->string
, pb
->string
);
2779 static bool font_setting(void)
2783 struct dirent
*entry
;
2791 dir
= rb
->opendir(FONT_DIR
);
2794 rb
->splash(HZ
/2, "Font dir is not accessible");
2800 entry
= rb
->readdir(dir
);
2805 len
= rb
->strlen(entry
->d_name
);
2806 if (len
< 4 || rb
->strcmp(entry
->d_name
+ len
-4, ".fnt"))
2813 struct opt_items names
[count
];
2814 unsigned char font_names
[size
];
2815 unsigned char *p
= font_names
;
2817 dir
= rb
->opendir(FONT_DIR
);
2820 rb
->splash(HZ
/2, "Font dir is not accessible");
2826 entry
= rb
->readdir(dir
);
2831 len
= rb
->strlen(entry
->d_name
);
2832 if (len
< 4 || rb
->strcmp(entry
->d_name
+ len
-4, ".fnt"))
2835 rb
->snprintf(p
, len
-3, "%s", entry
->d_name
);
2836 names
[i
].string
= p
;
2837 names
[i
].voice_id
= -1;
2845 rb
->qsort(names
, count
, sizeof(struct opt_items
), font_comp
);
2847 for (i
= 0; i
< count
; i
++)
2849 if (!rb
->strcmp(names
[i
].string
, prefs
.font
))
2855 old_font
= new_font
;
2857 res
= rb
->set_option("Select Font", &new_font
, INT
,
2858 names
, count
, NULL
);
2860 if (new_font
!= old_font
)
2862 /* load selected font */
2863 if (!change_font((unsigned char *)names
[new_font
].string
)) {
2864 /* revert by re-loading the preferences font */
2865 change_font(prefs
.font
);
2868 rb
->memset(prefs
.font
, 0, MAX_PATH
);
2869 rb
->snprintf(prefs
.font
, MAX_PATH
, "%s", names
[new_font
].string
);
2875 static bool alignment_setting(void)
2877 static const struct opt_items names
[] = {
2882 return rb
->set_option("Alignment", &prefs
.alignment
, INT
,
2887 static bool autoscroll_speed_setting(void)
2889 return rb
->set_int("Auto-scroll Speed", "", UNIT_INT
,
2890 &prefs
.autoscroll_speed
, NULL
, 1, 1, 10, NULL
);
2893 MENUITEM_FUNCTION(encoding_item
, 0, "Encoding", encoding_setting
,
2894 NULL
, NULL
, Icon_NOICON
);
2895 MENUITEM_FUNCTION(word_wrap_item
, 0, "Word Wrap", word_wrap_setting
,
2896 NULL
, NULL
, Icon_NOICON
);
2897 MENUITEM_FUNCTION(line_mode_item
, 0, "Line Mode", line_mode_setting
,
2898 NULL
, NULL
, Icon_NOICON
);
2899 MENUITEM_FUNCTION(view_mode_item
, 0, "Wide View", view_mode_setting
,
2900 NULL
, NULL
, Icon_NOICON
);
2901 #ifdef HAVE_LCD_BITMAP
2902 MENUITEM_FUNCTION(alignment_item
, 0, "Alignment", alignment_setting
,
2903 NULL
, NULL
, Icon_NOICON
);
2904 MENUITEM_FUNCTION(scrollbar_item
, 0, "Show Scrollbar", scrollbar_setting
,
2905 NULL
, NULL
, Icon_NOICON
);
2906 MENUITEM_FUNCTION(page_mode_item
, 0, "Overlap Pages", page_mode_setting
,
2907 NULL
, NULL
, Icon_NOICON
);
2908 MENUITEM_FUNCTION(header_item
, 0, "Show Header", header_setting
,
2909 NULL
, NULL
, Icon_NOICON
);
2910 MENUITEM_FUNCTION(footer_item
, 0, "Show Footer", footer_setting
,
2911 NULL
, NULL
, Icon_NOICON
);
2912 MENUITEM_FUNCTION(font_item
, 0, "Font", font_setting
,
2913 NULL
, NULL
, Icon_NOICON
);
2915 MENUITEM_FUNCTION(scroll_mode_item
, 0, "Scroll Mode", scroll_mode_setting
,
2916 NULL
, NULL
, Icon_NOICON
);
2917 MENUITEM_FUNCTION(autoscroll_speed_item
, 0, "Auto-Scroll Speed",
2918 autoscroll_speed_setting
, NULL
, NULL
, Icon_NOICON
);
2919 MAKE_MENU(option_menu
, "Viewer Options", NULL
, Icon_NOICON
,
2920 &encoding_item
, &word_wrap_item
, &line_mode_item
, &view_mode_item
,
2921 #ifdef HAVE_LCD_BITMAP
2922 &alignment_item
, &scrollbar_item
, &page_mode_item
, &header_item
,
2923 &footer_item
, &font_item
,
2925 &scroll_mode_item
, &autoscroll_speed_item
);
2927 static bool viewer_options_menu(bool is_global
)
2930 struct preferences tmp_prefs
;
2932 rb
->memcpy(&tmp_prefs
, &prefs
, sizeof(struct preferences
));
2934 result
= (rb
->do_menu(&option_menu
, NULL
, NULL
, false) == MENU_ATTACHED_USB
);
2936 if (!is_global
&& rb
->memcmp(&tmp_prefs
, &prefs
, sizeof(struct preferences
)))
2938 /* Show-scrollbar mode for current view-width mode */
2939 #ifdef HAVE_LCD_BITMAP
2940 init_need_scrollbar();
2941 init_header_and_footer();
2948 static void viewer_menu(void)
2952 MENUITEM_STRINGLIST(menu
, "Viewer Menu", NULL
,
2953 "Return", "Viewer Options",
2954 "Show Playback Menu", "Select Bookmark",
2955 "Global Settings", "Quit");
2957 result
= rb
->do_menu(&menu
, NULL
, NULL
, false);
2960 case 0: /* return */
2962 case 1: /* change settings */
2963 done
= viewer_options_menu(false);
2965 case 2: /* playback control */
2966 playback_control(NULL
);
2968 case 3: /* select bookmark */
2969 viewer_select_bookmark(viewer_add_last_read_bookmark());
2970 viewer_remove_last_read_bookmark();
2971 fill_buffer(file_pos
, buffer
, buffer_size
);
2972 if (prefs
.scroll_mode
== PAGE
&& cline
> 1)
2973 viewer_scroll_to_top_line();
2975 case 4: /* change global settings */
2977 struct preferences orig_prefs
;
2979 rb
->memcpy(&orig_prefs
, &prefs
, sizeof(struct preferences
));
2980 if (!viewer_load_global_settings())
2981 viewer_default_preferences();
2982 done
= viewer_options_menu(true);
2983 viewer_save_global_settings();
2984 rb
->memcpy(&prefs
, &orig_prefs
, sizeof(struct preferences
));
2995 enum plugin_status
plugin_start(const void* file
)
2998 int lastbutton
= BUTTON_NONE
;
2999 bool autoscroll
= false;
3002 old_tick
= *rb
->current_tick
;
3004 /* get the plugin buffer */
3005 buffer
= rb
->plugin_get_buffer((size_t *)&buffer_size
);
3006 if (buffer_size
== 0)
3008 rb
->splash(HZ
, "buffer does not allocate !!");
3009 return PLUGIN_ERROR
;
3011 block_size
= buffer_size
/ 3;
3012 buffer_size
= 3 * block_size
;
3015 return PLUGIN_ERROR
;
3020 rb
->splash(HZ
, "Error opening file.");
3021 return PLUGIN_ERROR
;
3024 if (!viewer_load_settings()) /* load the preferences and bookmark */
3025 return PLUGIN_ERROR
;
3028 rb
->lcd_set_backdrop(NULL
);
3037 if(old_tick
<= *rb
->current_tick
- (110-prefs
.autoscroll_speed
*10))
3039 viewer_scroll_down(true);
3041 old_tick
= *rb
->current_tick
;
3045 button
= rb
->button_get_w_tmo(HZ
/10);
3047 if (prefs
.view_mode
!= WIDE
) {
3048 /* when not in wide view mode, the SCREEN_LEFT and SCREEN_RIGHT
3049 buttons jump to the beginning and end of the file. To stop
3050 users doing this by accident, replace non-held occurrences
3051 with page up/down instead. */
3052 if (button
== VIEWER_SCREEN_LEFT
)
3053 button
= VIEWER_PAGE_UP
;
3054 else if (button
== VIEWER_SCREEN_RIGHT
)
3055 button
= VIEWER_PAGE_DOWN
;
3066 case VIEWER_AUTOSCROLL
:
3067 #ifdef VIEWER_AUTOSCROLL_PRE
3068 if (lastbutton
!= VIEWER_AUTOSCROLL_PRE
)
3071 autoscroll
= !autoscroll
;
3074 case VIEWER_PAGE_UP
:
3075 case VIEWER_PAGE_UP
| BUTTON_REPEAT
:
3076 #ifdef VIEWER_PAGE_UP2
3077 case VIEWER_PAGE_UP2
:
3078 case VIEWER_PAGE_UP2
| BUTTON_REPEAT
:
3080 if (prefs
.scroll_mode
== PAGE
)
3083 #ifdef HAVE_LCD_BITMAP
3084 for (i
= prefs
.page_mode
==OVERLAP
? 1:0; i
< display_lines
; i
++)
3086 for (i
= 0; i
< display_lines
; i
++)
3092 old_tick
= *rb
->current_tick
;
3096 case VIEWER_PAGE_DOWN
:
3097 case VIEWER_PAGE_DOWN
| BUTTON_REPEAT
:
3098 #ifdef VIEWER_PAGE_DOWN2
3099 case VIEWER_PAGE_DOWN2
:
3100 case VIEWER_PAGE_DOWN2
| BUTTON_REPEAT
:
3102 if (prefs
.scroll_mode
== PAGE
)
3105 if (next_screen_ptr
!= NULL
)
3107 screen_top_ptr
= next_screen_to_draw_ptr
;
3108 if (cpage
< MAX_PAGE
)
3113 viewer_scroll_down(autoscroll
);
3114 old_tick
= *rb
->current_tick
;
3118 case VIEWER_SCREEN_LEFT
:
3119 case VIEWER_SCREEN_LEFT
| BUTTON_REPEAT
:
3120 if (prefs
.view_mode
== WIDE
) {
3122 col
= col_limit(col
- draw_columns
);
3124 else { /* prefs.view_mode == NARROW */
3132 case VIEWER_SCREEN_RIGHT
:
3133 case VIEWER_SCREEN_RIGHT
| BUTTON_REPEAT
:
3134 if (prefs
.view_mode
== WIDE
) {
3136 col
= col_limit(col
+ draw_columns
);
3138 else { /* prefs.view_mode == NARROW */
3139 /* Bottom of file */
3146 #ifdef VIEWER_LINE_UP
3147 case VIEWER_LINE_UP
:
3148 case VIEWER_LINE_UP
| BUTTON_REPEAT
:
3149 /* Scroll up one line */
3151 old_tick
= *rb
->current_tick
;
3155 case VIEWER_LINE_DOWN
:
3156 case VIEWER_LINE_DOWN
| BUTTON_REPEAT
:
3157 /* Scroll down one line */
3158 viewer_scroll_down(autoscroll
);
3159 increment_current_line();
3160 old_tick
= *rb
->current_tick
;
3164 #ifdef VIEWER_COLUMN_LEFT
3165 case VIEWER_COLUMN_LEFT
:
3166 case VIEWER_COLUMN_LEFT
| BUTTON_REPEAT
:
3167 if (prefs
.view_mode
== WIDE
) {
3168 /* Scroll left one column */
3169 col
= col_limit(col
- glyph_width('o'));
3174 case VIEWER_COLUMN_RIGHT
:
3175 case VIEWER_COLUMN_RIGHT
| BUTTON_REPEAT
:
3176 if (prefs
.view_mode
== WIDE
) {
3177 /* Scroll right one column */
3178 col
= col_limit(col
+ glyph_width('o'));
3184 #ifdef VIEWER_RC_QUIT
3185 case VIEWER_RC_QUIT
:
3195 case VIEWER_BOOKMARK
:
3197 int idx
= viewer_find_bookmark(cpage
, cline
);
3201 if (bookmark_count
>= MAX_BOOKMARKS
-1)
3202 rb
->splash(HZ
/2, "No more add bookmark.");
3205 viewer_add_bookmark();
3206 rb
->splash(HZ
/2, "Bookmark add.");
3211 viewer_remove_bookmark(idx
);
3212 rb
->splash(HZ
/2, "Bookmark remove.");
3219 if (rb
->default_event_handler_ex(button
, viewer_exit
, NULL
)
3220 == SYS_USB_CONNECTED
)
3221 return PLUGIN_USB_CONNECTED
;
3224 if (button
!= BUTTON_NONE
)
3226 lastbutton
= button
;