1 /***************************************************************************
4 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
11 * Copyright (C) 2002 Gilles Roux, 2003 Garrett Derner
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
24 #include "lib/playback_control.h"
28 #define SETTINGS_FILE VIEWERS_DIR "/viewer.dat" /* binary file, so dont use .cfg */
29 #define BOOKMARKS_FILE VIEWERS_DIR "/viewer_bookmarks.dat"
31 #define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */
32 #define MAX_COLUMNS 64 /* Max displayable string len (over-estimate) */
33 #define MAX_WIDTH 910 /* Max line length in WIDE mode */
34 #define READ_PREV_ZONE 910 /* Arbitrary number less than SMALL_BLOCK_SIZE */
35 #define SMALL_BLOCK_SIZE 0x1000 /* 4k: Smallest file chunk we will read */
36 #define LARGE_BLOCK_SIZE 0x2000 /* 8k: Preferable size of file chunk to read */
37 #define TOP_SECTOR buffer
38 #define MID_SECTOR (buffer + SMALL_BLOCK_SIZE)
39 #define BOTTOM_SECTOR (buffer + 2*(SMALL_BLOCK_SIZE))
40 #undef SCROLLBAR_WIDTH
41 #define SCROLLBAR_WIDTH rb->global_settings->scrollbar_width
43 #define MAX_BOOKMARKED_FILES ((buffer_size/(signed)sizeof(struct bookmarked_file_info))-1)
45 /* Out-Of-Bounds test for any pointer to data in the buffer */
46 #define BUFFER_OOB(p) ((p) < buffer || (p) >= buffer_end)
48 /* Does the buffer contain the beginning of the file? */
49 #define BUFFER_BOF() (file_pos==0)
51 /* Does the buffer contain the end of the file? */
52 #define BUFFER_EOF() (file_size-file_pos <= buffer_size)
54 /* Formula for the endpoint address outside of buffer data */
55 #define BUFFER_END() \
56 ((BUFFER_EOF()) ? (file_size-file_pos+buffer) : (buffer+buffer_size))
58 /* Is the entire file being shown in one screen? */
59 #define ONE_SCREEN_FITS_ALL() \
60 (next_screen_ptr==NULL && screen_top_ptr==buffer && BUFFER_BOF())
62 /* Is a scrollbar called for on the current screen? */
63 #define NEED_SCROLLBAR() \
64 ((!(ONE_SCREEN_FITS_ALL())) && (prefs.scrollbar_mode==SB_ON))
66 /* variable button definitions */
69 #if CONFIG_KEYPAD == RECORDER_PAD
70 #define VIEWER_QUIT BUTTON_OFF
71 #define VIEWER_PAGE_UP BUTTON_UP
72 #define VIEWER_PAGE_DOWN BUTTON_DOWN
73 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
74 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
75 #define VIEWER_MENU BUTTON_F1
76 #define VIEWER_AUTOSCROLL BUTTON_PLAY
77 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
78 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
79 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
80 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
82 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
83 #define VIEWER_QUIT BUTTON_OFF
84 #define VIEWER_PAGE_UP BUTTON_UP
85 #define VIEWER_PAGE_DOWN BUTTON_DOWN
86 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
87 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
88 #define VIEWER_MENU BUTTON_F1
89 #define VIEWER_AUTOSCROLL BUTTON_SELECT
90 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
91 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
92 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
93 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
96 #elif CONFIG_KEYPAD == ONDIO_PAD
97 #define VIEWER_QUIT BUTTON_OFF
98 #define VIEWER_PAGE_UP BUTTON_UP
99 #define VIEWER_PAGE_DOWN BUTTON_DOWN
100 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
101 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
102 #define VIEWER_MENU (BUTTON_MENU|BUTTON_REPEAT)
103 #define VIEWER_AUTOSCROLL_PRE BUTTON_MENU
104 #define VIEWER_AUTOSCROLL (BUTTON_MENU|BUTTON_REL)
107 #elif CONFIG_KEYPAD == PLAYER_PAD
108 #define VIEWER_QUIT BUTTON_STOP
109 #define VIEWER_PAGE_UP BUTTON_LEFT
110 #define VIEWER_PAGE_DOWN BUTTON_RIGHT
111 #define VIEWER_SCREEN_LEFT (BUTTON_ON|BUTTON_LEFT)
112 #define VIEWER_SCREEN_RIGHT (BUTTON_ON|BUTTON_RIGHT)
113 #define VIEWER_MENU BUTTON_MENU
114 #define VIEWER_AUTOSCROLL BUTTON_PLAY
116 /* iRiver H1x0 && H3x0 keys */
117 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
118 (CONFIG_KEYPAD == IRIVER_H300_PAD)
119 #define VIEWER_QUIT BUTTON_OFF
120 #define VIEWER_PAGE_UP BUTTON_UP
121 #define VIEWER_PAGE_DOWN BUTTON_DOWN
122 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
123 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
124 #define VIEWER_MENU BUTTON_MODE
125 #define VIEWER_AUTOSCROLL BUTTON_SELECT
126 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
127 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
128 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
129 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
131 #define VIEWER_RC_QUIT BUTTON_RC_STOP
134 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
135 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
136 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
137 #define VIEWER_QUIT_PRE BUTTON_SELECT
138 #define VIEWER_QUIT (BUTTON_SELECT | BUTTON_MENU)
139 #define VIEWER_PAGE_UP BUTTON_SCROLL_BACK
140 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_FWD
141 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
142 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
143 #define VIEWER_MENU BUTTON_MENU
144 #define VIEWER_AUTOSCROLL BUTTON_PLAY
147 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
148 #define VIEWER_QUIT BUTTON_PLAY
149 #define VIEWER_PAGE_UP BUTTON_UP
150 #define VIEWER_PAGE_DOWN BUTTON_DOWN
151 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
152 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
153 #define VIEWER_MENU BUTTON_MODE
154 #define VIEWER_AUTOSCROLL BUTTON_SELECT
157 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
158 #define VIEWER_QUIT BUTTON_POWER
159 #define VIEWER_PAGE_UP BUTTON_UP
160 #define VIEWER_PAGE_DOWN BUTTON_DOWN
161 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
162 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
163 #define VIEWER_MENU BUTTON_SELECT
164 #define VIEWER_AUTOSCROLL BUTTON_PLAY
167 #elif CONFIG_KEYPAD == GIGABEAT_PAD
168 #define VIEWER_QUIT BUTTON_POWER
169 #define VIEWER_PAGE_UP BUTTON_UP
170 #define VIEWER_PAGE_DOWN BUTTON_DOWN
171 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
172 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
173 #define VIEWER_MENU BUTTON_MENU
174 #define VIEWER_AUTOSCROLL BUTTON_A
176 /* Sansa E200 keys */
177 #elif CONFIG_KEYPAD == SANSA_E200_PAD
178 #define VIEWER_QUIT BUTTON_POWER
179 #define VIEWER_PAGE_UP BUTTON_UP
180 #define VIEWER_PAGE_DOWN BUTTON_DOWN
181 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
182 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
183 #define VIEWER_MENU BUTTON_SELECT
184 #define VIEWER_AUTOSCROLL BUTTON_REC
185 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
186 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
188 /* Sansa Fuze keys */
189 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
190 #define VIEWER_QUIT (BUTTON_HOME|BUTTON_REPEAT)
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_SELECT|BUTTON_REPEAT
196 #define VIEWER_AUTOSCROLL BUTTON_SELECT|BUTTON_DOWN
197 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
198 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
200 /* Sansa C200 keys */
201 #elif CONFIG_KEYPAD == SANSA_C200_PAD
202 #define VIEWER_QUIT BUTTON_POWER
203 #define VIEWER_PAGE_UP BUTTON_VOL_UP
204 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
205 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
206 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
207 #define VIEWER_MENU BUTTON_SELECT
208 #define VIEWER_AUTOSCROLL BUTTON_REC
209 #define VIEWER_LINE_UP BUTTON_UP
210 #define VIEWER_LINE_DOWN BUTTON_DOWN
212 /* Sansa Clip keys */
213 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
214 #define VIEWER_QUIT BUTTON_POWER
215 #define VIEWER_PAGE_UP BUTTON_VOL_UP
216 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
217 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
218 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
219 #define VIEWER_MENU BUTTON_SELECT
220 #define VIEWER_AUTOSCROLL BUTTON_HOME
221 #define VIEWER_LINE_UP BUTTON_UP
222 #define VIEWER_LINE_DOWN BUTTON_DOWN
224 /* Sansa M200 keys */
225 #elif CONFIG_KEYPAD == SANSA_M200_PAD
226 #define VIEWER_QUIT BUTTON_POWER
227 #define VIEWER_PAGE_UP BUTTON_VOL_UP
228 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
229 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
230 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
231 #define VIEWER_MENU (BUTTON_SELECT | BUTTON_UP)
232 #define VIEWER_AUTOSCROLL (BUTTON_SELECT | BUTTON_REL)
233 #define VIEWER_LINE_UP BUTTON_UP
234 #define VIEWER_LINE_DOWN BUTTON_DOWN
236 /* iriver H10 keys */
237 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
238 #define VIEWER_QUIT BUTTON_POWER
239 #define VIEWER_PAGE_UP BUTTON_SCROLL_UP
240 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_DOWN
241 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
242 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
243 #define VIEWER_MENU BUTTON_REW
244 #define VIEWER_AUTOSCROLL BUTTON_PLAY
247 #elif CONFIG_KEYPAD == MROBE500_PAD
248 #define VIEWER_QUIT BUTTON_POWER
249 #define VIEWER_PAGE_UP BUTTON_RC_PLAY
250 #define VIEWER_PAGE_DOWN BUTTON_RC_DOWN
251 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
252 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
253 #define VIEWER_MENU BUTTON_RC_HEART
254 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
257 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
258 #define VIEWER_QUIT BUTTON_BACK
259 #define VIEWER_PAGE_UP BUTTON_PREV
260 #define VIEWER_PAGE_DOWN BUTTON_NEXT
261 #define VIEWER_SCREEN_LEFT (BUTTON_PLAY | BUTTON_LEFT)
262 #define VIEWER_SCREEN_RIGHT (BUTTON_PLAY | BUTTON_RIGHT)
263 #define VIEWER_MENU BUTTON_MENU
264 #define VIEWER_AUTOSCROLL_PRE BUTTON_PLAY
265 #define VIEWER_AUTOSCROLL (BUTTON_PLAY|BUTTON_REL)
266 #define VIEWER_LINE_UP BUTTON_UP
267 #define VIEWER_LINE_DOWN BUTTON_DOWN
268 #define VIEWER_COLUMN_LEFT BUTTON_LEFT
269 #define VIEWER_COLUMN_RIGHT BUTTON_RIGHT
272 #elif CONFIG_KEYPAD == MROBE100_PAD
273 #define VIEWER_QUIT BUTTON_POWER
274 #define VIEWER_PAGE_UP BUTTON_UP
275 #define VIEWER_PAGE_DOWN BUTTON_DOWN
276 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
277 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
278 #define VIEWER_MENU BUTTON_MENU
279 #define VIEWER_AUTOSCROLL BUTTON_DISPLAY
282 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
283 #define VIEWER_QUIT BUTTON_RC_REC
284 #define VIEWER_PAGE_UP BUTTON_RC_VOL_UP
285 #define VIEWER_PAGE_DOWN BUTTON_RC_VOL_DOWN
286 #define VIEWER_SCREEN_LEFT BUTTON_RC_REW
287 #define VIEWER_SCREEN_RIGHT BUTTON_RC_FF
288 #define VIEWER_MENU BUTTON_RC_MENU
289 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
290 #define VIEWER_RC_QUIT BUTTON_REC
293 #elif CONFIG_KEYPAD == COWOND2_PAD
294 #define VIEWER_QUIT BUTTON_POWER
295 #define VIEWER_MENU BUTTON_MENU
297 #elif CONFIG_KEYPAD == IAUDIO67_PAD
298 #define VIEWER_QUIT BUTTON_POWER
299 #define VIEWER_PAGE_UP BUTTON_VOLUP
300 #define VIEWER_PAGE_DOWN BUTTON_VOLDOWN
301 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
302 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
303 #define VIEWER_MENU BUTTON_MENU
304 #define VIEWER_AUTOSCROLL BUTTON_PLAY
305 #define VIEWER_RC_QUIT BUTTON_STOP
307 /* Creative Zen Vision:M keys */
308 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
309 #define VIEWER_QUIT BUTTON_BACK
310 #define VIEWER_PAGE_UP BUTTON_UP
311 #define VIEWER_PAGE_DOWN BUTTON_DOWN
312 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
313 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
314 #define VIEWER_MENU BUTTON_MENU
315 #define VIEWER_AUTOSCROLL BUTTON_SELECT
317 /* Philips HDD1630 keys */
318 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
319 #define VIEWER_QUIT BUTTON_POWER
320 #define VIEWER_PAGE_UP BUTTON_UP
321 #define VIEWER_PAGE_DOWN BUTTON_DOWN
322 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
323 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
324 #define VIEWER_MENU BUTTON_MENU
325 #define VIEWER_AUTOSCROLL BUTTON_VIEW
327 /* Onda VX747 keys */
328 #elif CONFIG_KEYPAD == ONDAVX747_PAD
329 #define VIEWER_QUIT BUTTON_POWER
330 #define VIEWER_MENU BUTTON_MENU
332 /* SAMSUNG YH-820 / YH-920 / YH-925 keys */
333 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
334 #define VIEWER_QUIT BUTTON_REC
335 #define VIEWER_PAGE_UP BUTTON_UP
336 #define VIEWER_PAGE_DOWN BUTTON_DOWN
337 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
338 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
339 #define VIEWER_MENU BUTTON_PLAY
340 #define VIEWER_AUTOSCROLL BUTTON_REW
343 #error No keymap defined!
346 #ifdef HAVE_TOUCHSCREEN
348 #define VIEWER_QUIT BUTTON_TOPLEFT
350 #ifndef VIEWER_PAGE_UP
351 #define VIEWER_PAGE_UP BUTTON_TOPMIDDLE
353 #ifndef VIEWER_PAGE_DOWN
354 #define VIEWER_PAGE_DOWN BUTTON_BOTTOMMIDDLE
356 #ifndef VIEWER_SCREEN_LEFT
357 #define VIEWER_SCREEN_LEFT BUTTON_MIDLEFT
359 #ifndef VIEWER_SCREEN_RIGHT
360 #define VIEWER_SCREEN_RIGHT BUTTON_MIDRIGHT
363 #define VIEWER_MENU BUTTON_TOPRIGHT
365 #ifndef VIEWER_AUTOSCROLL
366 #define VIEWER_AUTOSCROLL BUTTON_CENTER
370 /* stuff for the bookmarking */
371 struct bookmarked_file_info
{
374 char filename
[MAX_PATH
];
377 struct bookmark_file_data
{
378 signed int bookmarked_files_count
;
379 struct bookmarked_file_info bookmarks
[];
392 REFLOW
, /* won't be set on charcell LCD, must be last */
400 enum codepages encoding
;
402 #ifdef HAVE_LCD_BITMAP
413 #endif /* HAVE_LCD_BITMAP */
420 int autoscroll_speed
;
424 struct preferences prefs
;
425 struct preferences old_prefs
;
427 static unsigned char *buffer
;
428 static long buffer_size
;
429 static unsigned char line_break
[] = {0,0x20,9,0xB,0xC,'-'};
430 static int display_columns
; /* number of (pixel) columns on the display */
431 static int display_lines
; /* number of lines on the display */
432 static int draw_columns
; /* number of (pixel) columns available for text */
433 static int par_indent_spaces
; /* number of spaces to indent first paragraph */
435 static const char *file_name
;
436 static long file_size
;
437 static long start_position
; /* position in the file after the viewer is started */
438 static bool mac_text
;
439 static long file_pos
; /* Position of the top of the buffer in the file */
440 static unsigned char *buffer_end
; /*Set to BUFFER_END() when file_pos changes*/
441 static int max_line_len
;
442 static unsigned char *screen_top_ptr
;
443 static unsigned char *next_screen_ptr
;
444 static unsigned char *next_screen_to_draw_ptr
;
445 static unsigned char *next_line_ptr
;
446 #ifdef HAVE_LCD_BITMAP
447 static struct font
*pf
;
451 int glyph_width(int ch
)
456 #ifdef HAVE_LCD_BITMAP
457 return rb
->font_get_width(pf
, ch
);
463 unsigned char* get_ucs(const unsigned char* str
, unsigned short* ch
)
465 unsigned char utf8_tmp
[6];
468 if (prefs
.encoding
== UTF_8
)
469 return (unsigned char*)rb
->utf8decode(str
, ch
);
471 count
= BUFFER_OOB(str
+2)? 1:2;
472 rb
->iso_decode(str
, utf8_tmp
, prefs
.encoding
, count
);
473 rb
->utf8decode(utf8_tmp
, ch
);
475 #ifdef HAVE_LCD_BITMAP
476 if (prefs
.encoding
>= SJIS
&& *str
>= 0x80
477 && !(prefs
.encoding
== SJIS
&& *str
> 0xA0 && *str
< 0xE0))
478 return (unsigned char*)str
+2;
481 return (unsigned char*)str
+1;
487 #define ADVANCE_COUNTERS(c) { width += glyph_width(c); k++; }
488 #define LINE_IS_FULL ((k>=MAX_COLUMNS-1) ||( width >= draw_columns))
489 #define LINE_IS_NOT_FULL ((k<MAX_COLUMNS-1) &&( width < draw_columns))
490 static unsigned char* crop_at_width(const unsigned char* p
)
494 const unsigned char *oldp
= p
;
498 while (LINE_IS_NOT_FULL
) {
501 ADVANCE_COUNTERS(ch
);
504 return (unsigned char*)oldp
;
507 static unsigned char* find_first_feed(const unsigned char* p
, int size
)
511 for (i
=0; i
< size
; i
++)
513 return (unsigned char*) p
+i
;
518 static unsigned char* find_last_feed(const unsigned char* p
, int size
)
522 for (i
=size
-1; i
>=0; i
--)
524 return (unsigned char*) p
+i
;
529 static unsigned char* find_last_space(const unsigned char* p
, int size
)
533 k
= (prefs
.line_mode
==JOIN
) || (prefs
.line_mode
==REFLOW
) ? 0:1;
535 if (!BUFFER_OOB(&p
[size
]))
536 for (j
=k
; j
< ((int) sizeof(line_break
)) - 1; j
++)
537 if (p
[size
] == line_break
[j
])
538 return (unsigned char*) p
+size
;
540 for (i
=size
-1; i
>=0; i
--)
541 for (j
=k
; j
< (int) sizeof(line_break
); j
++)
543 if (!((p
[i
] == '-') && (prefs
.word_mode
== WRAP
)))
544 if (p
[i
] == line_break
[j
])
545 return (unsigned char*) p
+i
;
551 static unsigned char* find_next_line(const unsigned char* cur_line
, bool *is_short
)
553 const unsigned char *next_line
= NULL
;
554 int size
, i
, j
, k
, width
, search_len
, spaces
, newlines
;
558 if (is_short
!= NULL
)
561 if BUFFER_OOB(cur_line
)
564 if (prefs
.view_mode
== WIDE
) {
565 search_len
= MAX_WIDTH
;
567 else { /* prefs.view_mode == NARROW */
568 search_len
= crop_at_width(cur_line
) - cur_line
;
571 size
= BUFFER_OOB(cur_line
+search_len
) ? buffer_end
-cur_line
: search_len
;
573 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
)) {
574 /* Need to scan ahead and possibly increase search_len and size,
575 or possibly set next_line at second hard return in a row. */
578 for (j
=k
=width
=spaces
=newlines
=0; ; j
++) {
579 if (BUFFER_OOB(cur_line
+j
))
582 size
= search_len
= j
;
589 if (prefs
.line_mode
== REFLOW
) {
592 next_line
= cur_line
+ size
;
593 return (unsigned char*) next_line
;
595 if (j
==0) /* i=1 is intentional */
596 for (i
=0; i
<par_indent_spaces
; i
++)
597 ADVANCE_COUNTERS(' ');
599 if (!first_chars
) spaces
++;
605 next_line
= cur_line
+ size
- spaces
;
606 if (next_line
!= cur_line
)
607 return (unsigned char*) next_line
;
613 if (BUFFER_OOB(cur_line
+size
) || size
> 2*search_len
)
616 spaces
= first_chars
? 0:1;
620 if (prefs
.line_mode
==JOIN
|| newlines
>0) {
623 ADVANCE_COUNTERS(' ');
625 size
= search_len
= j
;
631 /* REFLOW, multiple spaces between words: count only
632 * one. If more are needed, they will be added
636 ADVANCE_COUNTERS(' ');
638 size
= search_len
= j
;
649 /* find first hard return */
650 next_line
= find_first_feed(cur_line
, size
);
653 if (next_line
== NULL
)
654 if (size
== search_len
) {
655 if (prefs
.word_mode
== WRAP
) /* Find last space */
656 next_line
= find_last_space(cur_line
, size
);
658 if (next_line
== NULL
)
659 next_line
= crop_at_width(cur_line
);
661 if (prefs
.word_mode
== WRAP
)
663 i
<WRAP_TRIM
&& isspace(next_line
[0]) && !BUFFER_OOB(next_line
);
668 if (prefs
.line_mode
== EXPAND
)
669 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
670 if (next_line
[0] == 0)
671 if (next_line
!= cur_line
)
672 return (unsigned char*) next_line
;
674 /* If next_line is pointing to a zero, increment it; i.e.,
675 leave the terminator at the end of cur_line. If pointing
676 to a hyphen, increment only if there is room to display
677 the hyphen on current line (won't apply in WIDE mode,
678 since it's guarenteed there won't be room). */
679 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
680 if (next_line
[0] == 0)/* ||
681 (next_line[0] == '-' && next_line-cur_line < draw_columns)) */
684 if (BUFFER_OOB(next_line
))
690 return (unsigned char*) next_line
;
693 static unsigned char* find_prev_line(const unsigned char* cur_line
)
695 const unsigned char *prev_line
= NULL
;
696 const unsigned char *p
;
698 if BUFFER_OOB(cur_line
)
701 /* To wrap consistently at the same places, we must
702 start with a known hard return, then work downwards.
703 We can either search backwards for a hard return,
704 or simply start wrapping downwards from top of buffer.
705 If current line is not near top of buffer, this is
706 a file with long lines (paragraphs). We would need to
707 read earlier sectors before we could decide how to
708 properly wrap the lines above the current line, but
709 it probably is not worth the disk access. Instead,
710 start with top of buffer and wrap down from there.
711 This may result in some lines wrapping at different
712 points from where they wrap when scrolling down.
713 If buffer is at top of file, start at top of buffer. */
715 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
))
716 prev_line
= p
= NULL
;
718 prev_line
= p
= find_last_feed(buffer
, cur_line
-buffer
-1);
719 /* Null means no line feeds in buffer above current line. */
721 if (prev_line
== NULL
)
722 if (BUFFER_BOF() || cur_line
- buffer
> READ_PREV_ZONE
)
723 prev_line
= p
= buffer
;
724 /* (else return NULL and read previous block) */
726 /* Wrap downwards until too far, then use the one before. */
727 while (p
< cur_line
&& p
!= NULL
) {
729 p
= find_next_line(prev_line
, NULL
);
732 if (BUFFER_OOB(prev_line
))
735 return (unsigned char*) prev_line
;
738 static void fill_buffer(long pos
, unsigned char* buf
, unsigned size
)
740 /* Read from file and preprocess the data */
741 /* To minimize disk access, always read on sector boundaries */
743 bool found_CR
= false;
745 rb
->lseek(fd
, pos
, SEEK_SET
);
746 numread
= rb
->read(fd
, buf
, size
);
747 rb
->button_clear_queue(); /* clear button queue */
749 for(i
= 0; i
< numread
; i
++) {
766 case 0: /* No break between case 0 and default, intentionally */
779 static int read_and_synch(int direction
)
781 /* Read next (or prev) block, and reposition global pointers. */
782 /* direction: 1 for down (i.e., further into file), -1 for up */
783 int move_size
, move_vector
, offset
;
784 unsigned char *fill_buf
;
786 if (direction
== -1) /* up */ {
787 move_size
= SMALL_BLOCK_SIZE
;
789 fill_buf
= TOP_SECTOR
;
790 rb
->memcpy(BOTTOM_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
791 rb
->memcpy(MID_SECTOR
, TOP_SECTOR
, SMALL_BLOCK_SIZE
);
794 if (prefs
.view_mode
== WIDE
) {
795 /* WIDE mode needs more buffer so we have to read smaller blocks */
796 move_size
= SMALL_BLOCK_SIZE
;
797 offset
= LARGE_BLOCK_SIZE
;
798 fill_buf
= BOTTOM_SECTOR
;
799 rb
->memcpy(TOP_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
800 rb
->memcpy(MID_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
803 move_size
= LARGE_BLOCK_SIZE
;
804 offset
= SMALL_BLOCK_SIZE
;
805 fill_buf
= MID_SECTOR
;
806 rb
->memcpy(TOP_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
809 move_vector
= direction
* move_size
;
810 screen_top_ptr
-= move_vector
;
811 file_pos
+= move_vector
;
812 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
813 fill_buffer(file_pos
+ offset
, fill_buf
, move_size
);
817 static void viewer_scroll_up(void)
821 p
= find_prev_line(screen_top_ptr
);
822 if (p
== NULL
&& !BUFFER_BOF()) {
824 p
= find_prev_line(screen_top_ptr
);
830 static void viewer_scroll_down(void)
832 if (next_screen_ptr
!= NULL
)
833 screen_top_ptr
= next_line_ptr
;
836 #ifdef HAVE_LCD_BITMAP
837 static void viewer_scrollbar(void) {
838 int items
, min_shown
, max_shown
;
840 items
= (int) file_size
; /* (SH1 int is same as long) */
841 min_shown
= (int) file_pos
+ (screen_top_ptr
- buffer
);
843 if (next_screen_ptr
== NULL
)
846 max_shown
= min_shown
+ (next_screen_ptr
- screen_top_ptr
);
848 rb
->gui_scrollbar_draw(rb
->screens
[SCREEN_MAIN
],0, 0, SCROLLBAR_WIDTH
-1,
849 LCD_HEIGHT
, items
, min_shown
, max_shown
, VERTICAL
);
853 static void viewer_draw(int col
)
855 int i
, j
, k
, line_len
, line_width
, resynch_move
, spaces
, left_col
=0;
856 int width
, extra_spaces
, indent_spaces
, spaces_per_word
;
857 bool multiple_spacing
, line_is_short
;
859 unsigned char *str
, *oldstr
;
860 unsigned char *line_begin
;
861 unsigned char *line_end
;
863 unsigned char scratch_buffer
[MAX_COLUMNS
+ 1];
864 unsigned char utf8_buffer
[MAX_COLUMNS
*4 + 1];
865 unsigned char *endptr
;
867 /* If col==-1 do all calculations but don't display */
869 #ifdef HAVE_LCD_BITMAP
870 left_col
= prefs
.need_scrollbar
? SCROLLBAR_WIDTH
:0;
874 rb
->lcd_clear_display();
877 line_begin
= line_end
= screen_top_ptr
;
879 for (i
= 0; i
< display_lines
; i
++) {
880 if (BUFFER_OOB(line_end
))
881 break; /* Happens after display last line at BUFFER_EOF() */
883 line_begin
= line_end
;
884 line_end
= find_next_line(line_begin
, &line_is_short
);
886 if (line_end
== NULL
) {
888 if (i
< display_lines
- 1 && !BUFFER_BOF()) {
890 rb
->lcd_clear_display();
892 for (; i
< display_lines
- 1; i
++)
895 line_begin
= line_end
= screen_top_ptr
;
900 line_end
= buffer_end
;
904 resynch_move
= read_and_synch(1); /* Read block & move ptrs */
905 line_begin
-= resynch_move
;
907 next_line_ptr
-= resynch_move
;
909 line_end
= find_next_line(line_begin
, NULL
);
910 if (line_end
== NULL
) /* Should not really happen */
914 line_len
= line_end
- line_begin
;
916 /* calculate line_len */
917 str
= oldstr
= line_begin
;
919 while (str
< line_end
) {
921 str
= crop_at_width(str
);
924 line_width
= j
*draw_columns
;
925 while (oldstr
< line_end
) {
926 oldstr
= get_ucs(oldstr
, &ch
);
927 line_width
+= glyph_width(ch
);
930 if (prefs
.line_mode
== JOIN
) {
931 if (line_begin
[0] == 0) {
933 if (prefs
.word_mode
== CHOP
)
938 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
939 if (k
== MAX_COLUMNS
)
949 scratch_buffer
[k
++] = ' ';
954 scratch_buffer
[k
++] = ' ';
955 if (k
== MAX_COLUMNS
- 1)
958 scratch_buffer
[k
++] = c
;
963 scratch_buffer
[k
] = 0;
964 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
965 prefs
.encoding
, draw_columns
/glyph_width('i'));
969 else if (prefs
.line_mode
== REFLOW
) {
970 if (line_begin
[0] == 0) {
972 if (prefs
.word_mode
== CHOP
)
979 if (!line_is_short
) {
980 multiple_spacing
= false;
982 for (str
= line_begin
; str
< line_end
; ) {
983 str
= get_ucs(str
, &ch
);
987 if ((str
== line_begin
) && (prefs
.word_mode
==WRAP
))
988 /* special case: indent the paragraph,
989 * don't count spaces */
990 indent_spaces
= par_indent_spaces
;
991 else if (!multiple_spacing
)
993 multiple_spacing
= true;
996 multiple_spacing
= false;
997 width
+= glyph_width(ch
);
1001 if (multiple_spacing
) spaces
--;
1004 /* total number of spaces to insert between words */
1005 extra_spaces
= (draw_columns
-width
)/glyph_width(' ')
1007 /* number of spaces between each word*/
1008 spaces_per_word
= extra_spaces
/ spaces
;
1009 /* number of words with n+1 spaces (to fill up) */
1010 extra_spaces
= extra_spaces
% spaces
;
1011 if (spaces_per_word
> 2) { /* too much spacing is awful */
1012 spaces_per_word
= 3;
1015 } else { /* this doesn't matter much... no spaces anyway */
1016 spaces_per_word
= extra_spaces
= 0;
1018 } else { /* end of a paragraph: don't fill line */
1019 spaces_per_word
= 1;
1023 multiple_spacing
= false;
1024 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
1025 if (k
== MAX_COLUMNS
)
1032 if (j
==0 && prefs
.word_mode
==WRAP
) { /* indent paragraph */
1033 for (j
=0; j
<par_indent_spaces
; j
++)
1034 scratch_buffer
[k
++] = ' ';
1037 else if (!multiple_spacing
) {
1038 for (width
= spaces
<extra_spaces
? -1:0; width
< spaces_per_word
; width
++)
1039 scratch_buffer
[k
++] = ' ';
1042 multiple_spacing
= true;
1045 scratch_buffer
[k
++] = c
;
1046 multiple_spacing
= false;
1052 scratch_buffer
[k
] = 0;
1053 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
1054 prefs
.encoding
, k
-col
);
1058 else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */
1060 if (line_width
> col
) {
1061 str
= oldstr
= line_begin
;
1064 while( (width
<draw_columns
) && (oldstr
<line_end
) )
1066 oldstr
= get_ucs(oldstr
, &ch
);
1068 k
-= glyph_width(ch
);
1069 line_begin
= oldstr
;
1071 width
+= glyph_width(ch
);
1075 if(prefs
.view_mode
==WIDE
)
1076 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1077 prefs
.encoding
, oldstr
-line_begin
);
1079 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1080 prefs
.encoding
, line_end
-line_begin
);
1084 if (col
!= -1 && line_width
> col
)
1085 #ifdef HAVE_LCD_BITMAP
1086 rb
->lcd_putsxy(left_col
, i
*pf
->height
, utf8_buffer
);
1088 rb
->lcd_puts(left_col
, i
, utf8_buffer
);
1090 if (line_width
> max_line_len
)
1091 max_line_len
= line_width
;
1094 next_line_ptr
= line_end
;
1096 next_screen_ptr
= line_end
;
1097 if (BUFFER_OOB(next_screen_ptr
))
1098 next_screen_ptr
= NULL
;
1100 #ifdef HAVE_LCD_BITMAP
1101 next_screen_to_draw_ptr
= prefs
.page_mode
==OVERLAP
? line_begin
: next_screen_ptr
;
1103 if (prefs
.need_scrollbar
)
1106 next_screen_to_draw_ptr
= next_screen_ptr
;
1113 static void viewer_top(void)
1115 /* Read top of file into buffer
1116 and point screen pointer to top */
1120 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1121 fill_buffer(0, buffer
, buffer_size
);
1124 screen_top_ptr
= buffer
;
1127 static void viewer_bottom(void)
1129 /* Read bottom of file into buffer
1130 and point screen pointer to bottom */
1133 if (file_size
> buffer_size
) {
1134 /* Find last buffer in file, round up to next sector boundary */
1135 last_sectors
= file_size
- buffer_size
+ SMALL_BLOCK_SIZE
;
1136 last_sectors
/= SMALL_BLOCK_SIZE
;
1137 last_sectors
*= SMALL_BLOCK_SIZE
;
1143 if (file_pos
!= last_sectors
)
1145 file_pos
= last_sectors
;
1146 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1147 fill_buffer(last_sectors
, buffer
, buffer_size
);
1150 screen_top_ptr
= buffer_end
-1;
1153 #ifdef HAVE_LCD_BITMAP
1154 static void init_need_scrollbar(void) {
1155 /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
1156 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
1158 prefs
.need_scrollbar
= NEED_SCROLLBAR();
1159 draw_columns
= prefs
.need_scrollbar
? display_columns
-SCROLLBAR_WIDTH
: display_columns
;
1160 par_indent_spaces
= draw_columns
/(5*glyph_width(' '));
1163 #define init_need_scrollbar()
1166 static bool viewer_init(void)
1168 #ifdef HAVE_LCD_BITMAP
1170 pf
= rb
->font_get(FONT_UI
);
1172 display_lines
= LCD_HEIGHT
/ pf
->height
;
1173 draw_columns
= display_columns
= LCD_WIDTH
;
1175 /* REAL fixed pitch :) all chars use up 1 cell */
1177 draw_columns
= display_columns
= 11;
1178 par_indent_spaces
= 2;
1181 fd
= rb
->open(file_name
, O_RDONLY
);
1185 file_size
= rb
->filesize(fd
);
1189 /* Init mac_text value used in processing buffer */
1195 static void viewer_default_settings(void)
1197 prefs
.word_mode
= WRAP
;
1198 prefs
.line_mode
= NORMAL
;
1199 prefs
.view_mode
= NARROW
;
1200 prefs
.scroll_mode
= PAGE
;
1201 #ifdef HAVE_LCD_BITMAP
1202 prefs
.page_mode
= NO_OVERLAP
;
1203 prefs
.scrollbar_mode
= SB_OFF
;
1205 prefs
.autoscroll_speed
= 1;
1206 /* Set codepage to system default */
1207 prefs
.encoding
= rb
->global_settings
->default_codepage
;
1210 static void viewer_load_settings(void) /* same name as global, but not the same file.. */
1213 struct bookmark_file_data
*data
;
1214 struct bookmarked_file_info this_bookmark
;
1216 /* read settings file */
1217 settings_fd
=rb
->open(SETTINGS_FILE
, O_RDONLY
);
1218 if ((settings_fd
>= 0) && (rb
->filesize(settings_fd
) == sizeof(struct preferences
)))
1220 rb
->read(settings_fd
, &prefs
, sizeof(struct preferences
));
1221 rb
->close(settings_fd
);
1225 /* load default settings if there is no settings file */
1226 viewer_default_settings();
1229 rb
->memcpy(&old_prefs
, &prefs
, sizeof(struct preferences
));
1231 data
= (struct bookmark_file_data
*)buffer
; /* grab the text buffer */
1232 data
->bookmarked_files_count
= 0;
1234 /* read bookmarks if file exists */
1235 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_RDONLY
);
1236 if (settings_fd
>= 0)
1238 /* figure out how many items to read */
1239 rb
->read(settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1240 if (data
->bookmarked_files_count
> MAX_BOOKMARKED_FILES
)
1241 data
->bookmarked_files_count
= MAX_BOOKMARKED_FILES
;
1242 rb
->read(settings_fd
, data
->bookmarks
,
1243 sizeof(struct bookmarked_file_info
) * data
->bookmarked_files_count
);
1244 rb
->close(settings_fd
);
1248 screen_top_ptr
= buffer
;
1250 /* check if current file is in list */
1251 for (i
=0; i
< data
->bookmarked_files_count
; i
++)
1253 if (!rb
->strcmp(file_name
, data
->bookmarks
[i
].filename
))
1255 int screen_pos
= data
->bookmarks
[i
].file_position
+ data
->bookmarks
[i
].top_ptr_pos
;
1256 int screen_top
= screen_pos
% buffer_size
;
1257 file_pos
= screen_pos
- screen_top
;
1258 screen_top_ptr
= buffer
+ screen_top
;
1263 this_bookmark
.file_position
= file_pos
;
1264 this_bookmark
.top_ptr_pos
= screen_top_ptr
- buffer
;
1266 rb
->memset(&this_bookmark
.filename
[0],0,MAX_PATH
);
1267 rb
->strcpy(this_bookmark
.filename
,file_name
);
1269 /* prevent potential slot overflow */
1270 if (i
>= data
->bookmarked_files_count
)
1272 if (i
< MAX_BOOKMARKED_FILES
)
1273 data
->bookmarked_files_count
++;
1275 i
= MAX_BOOKMARKED_FILES
-1;
1278 /* write bookmark file with spare slot in first position
1279 to be filled in by viewer_save_settings */
1280 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1281 if (settings_fd
>=0 )
1284 rb
->write (settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1286 /* write the current bookmark */
1287 rb
->write (settings_fd
, &this_bookmark
, sizeof(struct bookmarked_file_info
));
1289 /* write everything that was before this bookmark */
1290 rb
->write (settings_fd
, data
->bookmarks
, sizeof(struct bookmarked_file_info
)*i
);
1292 rb
->close(settings_fd
);
1295 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1297 if (BUFFER_OOB(screen_top_ptr
))
1299 screen_top_ptr
= buffer
;
1302 fill_buffer(file_pos
, buffer
, buffer_size
);
1304 /* remember the current position */
1305 start_position
= file_pos
+ screen_top_ptr
- buffer
;
1307 init_need_scrollbar();
1310 static void viewer_save_settings(void)/* same name as global, but not the same file.. */
1314 /* save the viewer settings if they have been changed */
1315 if (rb
->memcmp(&prefs
, &old_prefs
, sizeof(struct preferences
)))
1317 settings_fd
= rb
->creat(SETTINGS_FILE
); /* create the settings file */
1319 if (settings_fd
>= 0 )
1321 rb
->write (settings_fd
, &prefs
, sizeof(struct preferences
));
1322 rb
->close(settings_fd
);
1326 /* save the bookmark if the position has changed */
1327 if (file_pos
+ screen_top_ptr
- buffer
!= start_position
)
1329 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1331 if (settings_fd
>= 0 )
1333 struct bookmarked_file_info b
;
1334 b
.file_position
= file_pos
+ screen_top_ptr
- buffer
;
1335 b
.top_ptr_pos
= 0; /* this is only kept for legassy reasons */
1336 rb
->memset(&b
.filename
[0],0,MAX_PATH
);
1337 rb
->strcpy(b
.filename
,file_name
);
1338 rb
->lseek(settings_fd
,sizeof(signed int),SEEK_SET
);
1339 rb
->write (settings_fd
, &b
, sizeof(struct bookmarked_file_info
));
1340 rb
->close(settings_fd
);
1345 static void viewer_exit(void *parameter
)
1349 viewer_save_settings();
1353 static int col_limit(int col
)
1358 if (col
> max_line_len
- 2*glyph_width('o'))
1359 col
= max_line_len
- 2*glyph_width('o');
1364 /* settings helper functions */
1366 static bool encoding_setting(void)
1368 static struct opt_items names
[NUM_CODEPAGES
];
1371 for (idx
= 0; idx
< NUM_CODEPAGES
; idx
++)
1373 names
[idx
].string
= rb
->get_codepage_name(idx
);
1374 names
[idx
].voice_id
= -1;
1377 return rb
->set_option("Encoding", &prefs
.encoding
, INT
, names
,
1378 sizeof(names
) / sizeof(names
[0]), NULL
);
1381 static bool word_wrap_setting(void)
1383 static const struct opt_items names
[] = {
1385 {"Off (Chop Words)", -1},
1388 return rb
->set_option("Word Wrap", &prefs
.word_mode
, INT
,
1392 static bool line_mode_setting(void)
1394 static const struct opt_items names
[] = {
1397 {"Expand Lines", -1},
1398 #ifdef HAVE_LCD_BITMAP
1399 {"Reflow Lines", -1},
1403 return rb
->set_option("Line Mode", &prefs
.line_mode
, INT
, names
,
1404 sizeof(names
) / sizeof(names
[0]), NULL
);
1407 static bool view_mode_setting(void)
1409 static const struct opt_items names
[] = {
1410 {"No (Narrow)", -1},
1414 ret
= rb
->set_option("Wide View", &prefs
.view_mode
, INT
,
1416 if (prefs
.view_mode
== NARROW
)
1421 static bool scroll_mode_setting(void)
1423 static const struct opt_items names
[] = {
1424 {"Scroll by Page", -1},
1425 {"Scroll by Line", -1},
1428 return rb
->set_option("Scroll Mode", &prefs
.scroll_mode
, INT
,
1432 #ifdef HAVE_LCD_BITMAP
1433 static bool page_mode_setting(void)
1435 static const struct opt_items names
[] = {
1440 return rb
->set_option("Overlap Pages", &prefs
.page_mode
, INT
,
1444 static bool scrollbar_setting(void)
1446 static const struct opt_items names
[] = {
1451 return rb
->set_option("Show Scrollbar", &prefs
.scrollbar_mode
, INT
,
1456 static bool autoscroll_speed_setting(void)
1458 return rb
->set_int("Auto-scroll Speed", "", UNIT_INT
,
1459 &prefs
.autoscroll_speed
, NULL
, 1, 1, 10, NULL
);
1462 MENUITEM_FUNCTION(encoding_item
, 0, "Encoding", encoding_setting
,
1463 NULL
, NULL
, Icon_NOICON
);
1464 MENUITEM_FUNCTION(word_wrap_item
, 0, "Word Wrap", word_wrap_setting
,
1465 NULL
, NULL
, Icon_NOICON
);
1466 MENUITEM_FUNCTION(line_mode_item
, 0, "Line Mode", line_mode_setting
,
1467 NULL
, NULL
, Icon_NOICON
);
1468 MENUITEM_FUNCTION(view_mode_item
, 0, "Wide View", view_mode_setting
,
1469 NULL
, NULL
, Icon_NOICON
);
1470 #ifdef HAVE_LCD_BITMAP
1471 MENUITEM_FUNCTION(scrollbar_item
, 0, "Show Scrollbar", scrollbar_setting
,
1472 NULL
, NULL
, Icon_NOICON
);
1473 MENUITEM_FUNCTION(page_mode_item
, 0, "Overlap Pages", page_mode_setting
,
1474 NULL
, NULL
, Icon_NOICON
);
1476 MENUITEM_FUNCTION(scroll_mode_item
, 0, "Scroll Mode", scroll_mode_setting
,
1477 NULL
, NULL
, Icon_NOICON
);
1478 MENUITEM_FUNCTION(autoscroll_speed_item
, 0, "Auto-Scroll Speed",
1479 autoscroll_speed_setting
, NULL
, NULL
, Icon_NOICON
);
1480 MAKE_MENU(option_menu
, "Viewer Options", NULL
, Icon_NOICON
,
1481 &encoding_item
, &word_wrap_item
, &line_mode_item
, &view_mode_item
,
1482 #ifdef HAVE_LCD_BITMAP
1483 &scrollbar_item
, &page_mode_item
,
1485 &scroll_mode_item
, &autoscroll_speed_item
);
1487 static bool viewer_options_menu(void)
1490 result
= (rb
->do_menu(&option_menu
, NULL
, NULL
, false) == MENU_ATTACHED_USB
);
1492 #ifdef HAVE_LCD_BITMAP
1493 /* Show-scrollbar mode for current view-width mode */
1494 init_need_scrollbar();
1499 static void viewer_menu(void)
1502 MENUITEM_STRINGLIST(menu
, "Viewer Menu", NULL
,
1503 "Return", "Viewer Options",
1504 "Show Playback Menu", "Quit");
1506 result
= rb
->do_menu(&menu
, NULL
, NULL
, false);
1509 case 0: /* return */
1511 case 1: /* change settings */
1512 done
= viewer_options_menu();
1514 case 2: /* playback control */
1515 playback_control(NULL
);
1525 enum plugin_status
plugin_start(const void* file
)
1528 int lastbutton
= BUTTON_NONE
;
1529 bool autoscroll
= false;
1532 old_tick
= *rb
->current_tick
;
1534 /* get the plugin buffer */
1535 buffer
= rb
->plugin_get_buffer((size_t *)&buffer_size
);
1538 return PLUGIN_ERROR
;
1543 rb
->splash(HZ
, "Error opening file.");
1544 return PLUGIN_ERROR
;
1547 viewer_load_settings(); /* load the preferences and bookmark */
1550 rb
->lcd_set_backdrop(NULL
);
1559 if(old_tick
<= *rb
->current_tick
- (110-prefs
.autoscroll_speed
*10))
1561 viewer_scroll_down();
1563 old_tick
= *rb
->current_tick
;
1567 button
= rb
->button_get_w_tmo(HZ
/10);
1573 case VIEWER_AUTOSCROLL
:
1574 #ifdef VIEWER_AUTOSCROLL_PRE
1575 if (lastbutton
!= VIEWER_AUTOSCROLL_PRE
)
1578 autoscroll
= !autoscroll
;
1581 case VIEWER_PAGE_UP
:
1582 case VIEWER_PAGE_UP
| BUTTON_REPEAT
:
1583 if (prefs
.scroll_mode
== PAGE
)
1586 #ifdef HAVE_LCD_BITMAP
1587 for (i
= prefs
.page_mode
==OVERLAP
? 1:0; i
< display_lines
; i
++)
1589 for (i
= 0; i
< display_lines
; i
++)
1595 old_tick
= *rb
->current_tick
;
1599 case VIEWER_PAGE_DOWN
:
1600 case VIEWER_PAGE_DOWN
| BUTTON_REPEAT
:
1601 if (prefs
.scroll_mode
== PAGE
)
1604 if (next_screen_ptr
!= NULL
)
1605 screen_top_ptr
= next_screen_to_draw_ptr
;
1608 viewer_scroll_down();
1609 old_tick
= *rb
->current_tick
;
1613 case VIEWER_SCREEN_LEFT
:
1614 case VIEWER_SCREEN_LEFT
| BUTTON_REPEAT
:
1615 if (prefs
.view_mode
== WIDE
) {
1617 col
-= draw_columns
;
1618 col
= col_limit(col
);
1620 else { /* prefs.view_mode == NARROW */
1628 case VIEWER_SCREEN_RIGHT
:
1629 case VIEWER_SCREEN_RIGHT
| BUTTON_REPEAT
:
1630 if (prefs
.view_mode
== WIDE
) {
1632 col
+= draw_columns
;
1633 col
= col_limit(col
);
1635 else { /* prefs.view_mode == NARROW */
1636 /* Bottom of file */
1643 #ifdef VIEWER_LINE_UP
1644 case VIEWER_LINE_UP
:
1645 case VIEWER_LINE_UP
| BUTTON_REPEAT
:
1646 /* Scroll up one line */
1648 old_tick
= *rb
->current_tick
;
1652 case VIEWER_LINE_DOWN
:
1653 case VIEWER_LINE_DOWN
| BUTTON_REPEAT
:
1654 /* Scroll down one line */
1655 if (next_screen_ptr
!= NULL
)
1656 screen_top_ptr
= next_line_ptr
;
1657 old_tick
= *rb
->current_tick
;
1661 #ifdef VIEWER_COLUMN_LEFT
1662 case VIEWER_COLUMN_LEFT
:
1663 case VIEWER_COLUMN_LEFT
| BUTTON_REPEAT
:
1664 if (prefs
.view_mode
== WIDE
) {
1665 /* Scroll left one column */
1666 col
-= glyph_width('o');
1667 col
= col_limit(col
);
1672 case VIEWER_COLUMN_RIGHT
:
1673 case VIEWER_COLUMN_RIGHT
| BUTTON_REPEAT
:
1674 if (prefs
.view_mode
== WIDE
) {
1675 /* Scroll right one column */
1676 col
+= glyph_width('o');
1677 col
= col_limit(col
);
1683 #ifdef VIEWER_RC_QUIT
1684 case VIEWER_RC_QUIT
:
1692 if (rb
->default_event_handler_ex(button
, viewer_exit
, NULL
)
1693 == SYS_USB_CONNECTED
)
1694 return PLUGIN_USB_CONNECTED
;
1697 if (button
!= BUTTON_NONE
)
1699 lastbutton
= button
;