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"
25 #include "lib/oldmenuapi.h"
29 #define SETTINGS_FILE VIEWERS_DIR "/viewer.dat" /* binary file, so dont use .cfg */
30 #define BOOKMARKS_FILE VIEWERS_DIR "/viewer_bookmarks.dat"
32 #define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */
33 #define MAX_COLUMNS 64 /* Max displayable string len (over-estimate) */
34 #define MAX_WIDTH 910 /* Max line length in WIDE mode */
35 #define READ_PREV_ZONE 910 /* Arbitrary number less than SMALL_BLOCK_SIZE */
36 #define SMALL_BLOCK_SIZE 0x1000 /* 4k: Smallest file chunk we will read */
37 #define LARGE_BLOCK_SIZE 0x2000 /* 8k: Preferable size of file chunk to read */
38 #define TOP_SECTOR buffer
39 #define MID_SECTOR (buffer + SMALL_BLOCK_SIZE)
40 #define BOTTOM_SECTOR (buffer + 2*(SMALL_BLOCK_SIZE))
41 #define SCROLLBAR_WIDTH 6
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_POWER
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
328 #error No keymap defined!
331 #ifdef HAVE_TOUCHSCREEN
333 #define VIEWER_QUIT BUTTON_TOPLEFT
335 #ifndef VIEWER_PAGE_UP
336 #define VIEWER_PAGE_UP BUTTON_TOPMIDDLE
338 #ifndef VIEWER_PAGE_DOWN
339 #define VIEWER_PAGE_DOWN BUTTON_BOTTOMMIDDLE
341 #ifndef VIEWER_SCREEN_LEFT
342 #define VIEWER_SCREEN_LEFT BUTTON_MIDLEFT
344 #ifndef VIEWER_SCREEN_RIGHT
345 #define VIEWER_SCREEN_RIGHT BUTTON_MIDRIGHT
348 #define VIEWER_MENU BUTTON_TOPRIGHT
350 #ifndef VIEWER_AUTOSCROLL
351 #define VIEWER_AUTOSCROLL BUTTON_CENTER
355 /* stuff for the bookmarking */
356 struct bookmarked_file_info
{
359 char filename
[MAX_PATH
];
362 struct bookmark_file_data
{
363 signed int bookmarked_files_count
;
364 struct bookmarked_file_info bookmarks
[];
377 REFLOW
, /* won't be set on charcell LCD, must be last */
385 enum codepages encoding
;
387 #ifdef HAVE_LCD_BITMAP
398 #endif /* HAVE_LCD_BITMAP */
405 int autoscroll_speed
;
409 struct preferences prefs
;
410 struct preferences old_prefs
;
412 static unsigned char *buffer
;
413 static long buffer_size
;
414 static unsigned char line_break
[] = {0,0x20,9,0xB,0xC,'-'};
415 static int display_columns
; /* number of (pixel) columns on the display */
416 static int display_lines
; /* number of lines on the display */
417 static int draw_columns
; /* number of (pixel) columns available for text */
418 static int par_indent_spaces
; /* number of spaces to indent first paragraph */
420 static const char *file_name
;
421 static long file_size
;
422 static long start_position
; /* position in the file after the viewer is started */
423 static bool mac_text
;
424 static long file_pos
; /* Position of the top of the buffer in the file */
425 static unsigned char *buffer_end
; /*Set to BUFFER_END() when file_pos changes*/
426 static int max_line_len
;
427 static unsigned char *screen_top_ptr
;
428 static unsigned char *next_screen_ptr
;
429 static unsigned char *next_screen_to_draw_ptr
;
430 static unsigned char *next_line_ptr
;
431 #ifdef HAVE_LCD_BITMAP
432 static struct font
*pf
;
436 int glyph_width(int ch
)
441 #ifdef HAVE_LCD_BITMAP
442 return rb
->font_get_width(pf
, ch
);
448 unsigned char* get_ucs(const unsigned char* str
, unsigned short* ch
)
450 unsigned char utf8_tmp
[6];
453 if (prefs
.encoding
== UTF_8
)
454 return (unsigned char*)rb
->utf8decode(str
, ch
);
456 count
= BUFFER_OOB(str
+2)? 1:2;
457 rb
->iso_decode(str
, utf8_tmp
, prefs
.encoding
, count
);
458 rb
->utf8decode(utf8_tmp
, ch
);
460 #ifdef HAVE_LCD_BITMAP
461 if ((prefs
.encoding
== SJIS
&& *str
> 0xA0 && *str
< 0xE0) || prefs
.encoding
< SJIS
)
462 return (unsigned char*)str
+1;
465 return (unsigned char*)str
+2;
471 #define ADVANCE_COUNTERS(c) { width += glyph_width(c); k++; }
472 #define LINE_IS_FULL ((k>=MAX_COLUMNS-1) ||( width >= draw_columns))
473 #define LINE_IS_NOT_FULL ((k<MAX_COLUMNS-1) &&( width < draw_columns))
474 static unsigned char* crop_at_width(const unsigned char* p
)
478 const unsigned char *oldp
= p
;
482 while (LINE_IS_NOT_FULL
) {
485 ADVANCE_COUNTERS(ch
);
488 return (unsigned char*)oldp
;
491 static unsigned char* find_first_feed(const unsigned char* p
, int size
)
495 for (i
=0; i
< size
; i
++)
497 return (unsigned char*) p
+i
;
502 static unsigned char* find_last_feed(const unsigned char* p
, int size
)
506 for (i
=size
-1; i
>=0; i
--)
508 return (unsigned char*) p
+i
;
513 static unsigned char* find_last_space(const unsigned char* p
, int size
)
517 k
= (prefs
.line_mode
==JOIN
) || (prefs
.line_mode
==REFLOW
) ? 0:1;
519 if (!BUFFER_OOB(&p
[size
]))
520 for (j
=k
; j
< ((int) sizeof(line_break
)) - 1; j
++)
521 if (p
[size
] == line_break
[j
])
522 return (unsigned char*) p
+size
;
524 for (i
=size
-1; i
>=0; i
--)
525 for (j
=k
; j
< (int) sizeof(line_break
); j
++)
527 if (!((p
[i
] == '-') && (prefs
.word_mode
== WRAP
)))
528 if (p
[i
] == line_break
[j
])
529 return (unsigned char*) p
+i
;
535 static unsigned char* find_next_line(const unsigned char* cur_line
, bool *is_short
)
537 const unsigned char *next_line
= NULL
;
538 int size
, i
, j
, k
, width
, search_len
, spaces
, newlines
;
542 if (is_short
!= NULL
)
545 if BUFFER_OOB(cur_line
)
548 if (prefs
.view_mode
== WIDE
) {
549 search_len
= MAX_WIDTH
;
551 else { /* prefs.view_mode == NARROW */
552 search_len
= crop_at_width(cur_line
) - cur_line
;
555 size
= BUFFER_OOB(cur_line
+search_len
) ? buffer_end
-cur_line
: search_len
;
557 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
)) {
558 /* Need to scan ahead and possibly increase search_len and size,
559 or possibly set next_line at second hard return in a row. */
562 for (j
=k
=width
=spaces
=newlines
=0; ; j
++) {
563 if (BUFFER_OOB(cur_line
+j
))
566 size
= search_len
= j
;
573 if (prefs
.line_mode
== REFLOW
) {
576 next_line
= cur_line
+ size
;
577 return (unsigned char*) next_line
;
579 if (j
==0) /* i=1 is intentional */
580 for (i
=0; i
<par_indent_spaces
; i
++)
581 ADVANCE_COUNTERS(' ');
583 if (!first_chars
) spaces
++;
589 next_line
= cur_line
+ size
- spaces
;
590 if (next_line
!= cur_line
)
591 return (unsigned char*) next_line
;
597 if (BUFFER_OOB(cur_line
+size
) || size
> 2*search_len
)
600 spaces
= first_chars
? 0:1;
604 if (prefs
.line_mode
==JOIN
|| newlines
>0) {
607 ADVANCE_COUNTERS(' ');
609 size
= search_len
= j
;
615 /* REFLOW, multiple spaces between words: count only
616 * one. If more are needed, they will be added
620 ADVANCE_COUNTERS(' ');
622 size
= search_len
= j
;
633 /* find first hard return */
634 next_line
= find_first_feed(cur_line
, size
);
637 if (next_line
== NULL
)
638 if (size
== search_len
) {
639 if (prefs
.word_mode
== WRAP
) /* Find last space */
640 next_line
= find_last_space(cur_line
, size
);
642 if (next_line
== NULL
)
643 next_line
= crop_at_width(cur_line
);
645 if (prefs
.word_mode
== WRAP
)
647 i
<WRAP_TRIM
&& isspace(next_line
[0]) && !BUFFER_OOB(next_line
);
652 if (prefs
.line_mode
== EXPAND
)
653 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
654 if (next_line
[0] == 0)
655 if (next_line
!= cur_line
)
656 return (unsigned char*) next_line
;
658 /* If next_line is pointing to a zero, increment it; i.e.,
659 leave the terminator at the end of cur_line. If pointing
660 to a hyphen, increment only if there is room to display
661 the hyphen on current line (won't apply in WIDE mode,
662 since it's guarenteed there won't be room). */
663 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
664 if (next_line
[0] == 0)/* ||
665 (next_line[0] == '-' && next_line-cur_line < draw_columns)) */
668 if (BUFFER_OOB(next_line
))
674 return (unsigned char*) next_line
;
677 static unsigned char* find_prev_line(const unsigned char* cur_line
)
679 const unsigned char *prev_line
= NULL
;
680 const unsigned char *p
;
682 if BUFFER_OOB(cur_line
)
685 /* To wrap consistently at the same places, we must
686 start with a known hard return, then work downwards.
687 We can either search backwards for a hard return,
688 or simply start wrapping downwards from top of buffer.
689 If current line is not near top of buffer, this is
690 a file with long lines (paragraphs). We would need to
691 read earlier sectors before we could decide how to
692 properly wrap the lines above the current line, but
693 it probably is not worth the disk access. Instead,
694 start with top of buffer and wrap down from there.
695 This may result in some lines wrapping at different
696 points from where they wrap when scrolling down.
697 If buffer is at top of file, start at top of buffer. */
699 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
))
700 prev_line
= p
= NULL
;
702 prev_line
= p
= find_last_feed(buffer
, cur_line
-buffer
-1);
703 /* Null means no line feeds in buffer above current line. */
705 if (prev_line
== NULL
)
706 if (BUFFER_BOF() || cur_line
- buffer
> READ_PREV_ZONE
)
707 prev_line
= p
= buffer
;
708 /* (else return NULL and read previous block) */
710 /* Wrap downwards until too far, then use the one before. */
711 while (p
< cur_line
&& p
!= NULL
) {
713 p
= find_next_line(prev_line
, NULL
);
716 if (BUFFER_OOB(prev_line
))
719 return (unsigned char*) prev_line
;
722 static void fill_buffer(long pos
, unsigned char* buf
, unsigned size
)
724 /* Read from file and preprocess the data */
725 /* To minimize disk access, always read on sector boundaries */
727 bool found_CR
= false;
729 rb
->lseek(fd
, pos
, SEEK_SET
);
730 numread
= rb
->read(fd
, buf
, size
);
731 rb
->button_clear_queue(); /* clear button queue */
733 for(i
= 0; i
< numread
; i
++) {
750 case 0: /* No break between case 0 and default, intentionally */
763 static int read_and_synch(int direction
)
765 /* Read next (or prev) block, and reposition global pointers. */
766 /* direction: 1 for down (i.e., further into file), -1 for up */
767 int move_size
, move_vector
, offset
;
768 unsigned char *fill_buf
;
770 if (direction
== -1) /* up */ {
771 move_size
= SMALL_BLOCK_SIZE
;
773 fill_buf
= TOP_SECTOR
;
774 rb
->memcpy(BOTTOM_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
775 rb
->memcpy(MID_SECTOR
, TOP_SECTOR
, SMALL_BLOCK_SIZE
);
778 if (prefs
.view_mode
== WIDE
) {
779 /* WIDE mode needs more buffer so we have to read smaller blocks */
780 move_size
= SMALL_BLOCK_SIZE
;
781 offset
= LARGE_BLOCK_SIZE
;
782 fill_buf
= BOTTOM_SECTOR
;
783 rb
->memcpy(TOP_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
784 rb
->memcpy(MID_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
787 move_size
= LARGE_BLOCK_SIZE
;
788 offset
= SMALL_BLOCK_SIZE
;
789 fill_buf
= MID_SECTOR
;
790 rb
->memcpy(TOP_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
793 move_vector
= direction
* move_size
;
794 screen_top_ptr
-= move_vector
;
795 file_pos
+= move_vector
;
796 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
797 fill_buffer(file_pos
+ offset
, fill_buf
, move_size
);
801 static void viewer_scroll_up(void)
805 p
= find_prev_line(screen_top_ptr
);
806 if (p
== NULL
&& !BUFFER_BOF()) {
808 p
= find_prev_line(screen_top_ptr
);
814 static void viewer_scroll_down(void)
816 if (next_screen_ptr
!= NULL
)
817 screen_top_ptr
= next_line_ptr
;
820 #ifdef HAVE_LCD_BITMAP
821 static void viewer_scrollbar(void) {
822 int items
, min_shown
, max_shown
;
824 items
= (int) file_size
; /* (SH1 int is same as long) */
825 min_shown
= (int) file_pos
+ (screen_top_ptr
- buffer
);
827 if (next_screen_ptr
== NULL
)
830 max_shown
= min_shown
+ (next_screen_ptr
- screen_top_ptr
);
832 rb
->gui_scrollbar_draw(rb
->screens
[SCREEN_MAIN
],0, 0, SCROLLBAR_WIDTH
-1,
833 LCD_HEIGHT
, items
, min_shown
, max_shown
, VERTICAL
);
837 static void viewer_draw(int col
)
839 int i
, j
, k
, line_len
, line_width
, resynch_move
, spaces
, left_col
=0;
840 int width
, extra_spaces
, indent_spaces
, spaces_per_word
;
841 bool multiple_spacing
, line_is_short
;
843 unsigned char *str
, *oldstr
;
844 unsigned char *line_begin
;
845 unsigned char *line_end
;
847 unsigned char scratch_buffer
[MAX_COLUMNS
+ 1];
848 unsigned char utf8_buffer
[MAX_COLUMNS
*4 + 1];
849 unsigned char *endptr
;
851 /* If col==-1 do all calculations but don't display */
853 #ifdef HAVE_LCD_BITMAP
854 left_col
= prefs
.need_scrollbar
? SCROLLBAR_WIDTH
:0;
858 rb
->lcd_clear_display();
861 line_begin
= line_end
= screen_top_ptr
;
863 for (i
= 0; i
< display_lines
; i
++) {
864 if (BUFFER_OOB(line_end
))
865 break; /* Happens after display last line at BUFFER_EOF() */
867 line_begin
= line_end
;
868 line_end
= find_next_line(line_begin
, &line_is_short
);
870 if (line_end
== NULL
) {
872 if (i
< display_lines
- 1 && !BUFFER_BOF()) {
874 rb
->lcd_clear_display();
876 for (; i
< display_lines
- 1; i
++)
879 line_begin
= line_end
= screen_top_ptr
;
884 line_end
= buffer_end
;
888 resynch_move
= read_and_synch(1); /* Read block & move ptrs */
889 line_begin
-= resynch_move
;
891 next_line_ptr
-= resynch_move
;
893 line_end
= find_next_line(line_begin
, NULL
);
894 if (line_end
== NULL
) /* Should not really happen */
898 line_len
= line_end
- line_begin
;
900 /* calculate line_len */
901 str
= oldstr
= line_begin
;
903 while (str
< line_end
) {
905 str
= crop_at_width(str
);
908 line_width
= j
*draw_columns
;
909 while (oldstr
< line_end
) {
910 oldstr
= get_ucs(oldstr
, &ch
);
911 line_width
+= glyph_width(ch
);
914 if (prefs
.line_mode
== JOIN
) {
915 if (line_begin
[0] == 0) {
917 if (prefs
.word_mode
== CHOP
)
922 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
923 if (k
== MAX_COLUMNS
)
933 scratch_buffer
[k
++] = ' ';
938 scratch_buffer
[k
++] = ' ';
939 if (k
== MAX_COLUMNS
- 1)
942 scratch_buffer
[k
++] = c
;
947 scratch_buffer
[k
] = 0;
948 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
949 prefs
.encoding
, draw_columns
/glyph_width('i'));
953 else if (prefs
.line_mode
== REFLOW
) {
954 if (line_begin
[0] == 0) {
956 if (prefs
.word_mode
== CHOP
)
963 if (!line_is_short
) {
964 multiple_spacing
= false;
966 for (str
= line_begin
; str
< line_end
; ) {
967 str
= get_ucs(str
, &ch
);
971 if ((str
== line_begin
) && (prefs
.word_mode
==WRAP
))
972 /* special case: indent the paragraph,
973 * don't count spaces */
974 indent_spaces
= par_indent_spaces
;
975 else if (!multiple_spacing
)
977 multiple_spacing
= true;
980 multiple_spacing
= false;
981 width
+= glyph_width(ch
);
985 if (multiple_spacing
) spaces
--;
988 /* total number of spaces to insert between words */
989 extra_spaces
= (draw_columns
-width
)/glyph_width(' ')
991 /* number of spaces between each word*/
992 spaces_per_word
= extra_spaces
/ spaces
;
993 /* number of words with n+1 spaces (to fill up) */
994 extra_spaces
= extra_spaces
% spaces
;
995 if (spaces_per_word
> 2) { /* too much spacing is awful */
999 } else { /* this doesn't matter much... no spaces anyway */
1000 spaces_per_word
= extra_spaces
= 0;
1002 } else { /* end of a paragraph: don't fill line */
1003 spaces_per_word
= 1;
1007 multiple_spacing
= false;
1008 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
1009 if (k
== MAX_COLUMNS
)
1016 if (j
==0 && prefs
.word_mode
==WRAP
) { /* indent paragraph */
1017 for (j
=0; j
<par_indent_spaces
; j
++)
1018 scratch_buffer
[k
++] = ' ';
1021 else if (!multiple_spacing
) {
1022 for (width
= spaces
<extra_spaces
? -1:0; width
< spaces_per_word
; width
++)
1023 scratch_buffer
[k
++] = ' ';
1026 multiple_spacing
= true;
1029 scratch_buffer
[k
++] = c
;
1030 multiple_spacing
= false;
1036 scratch_buffer
[k
] = 0;
1037 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
1038 prefs
.encoding
, k
-col
);
1042 else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */
1044 if (line_width
> col
) {
1045 str
= oldstr
= line_begin
;
1048 while( (width
<draw_columns
) && (oldstr
<line_end
) )
1050 oldstr
= get_ucs(oldstr
, &ch
);
1052 k
-= glyph_width(ch
);
1053 line_begin
= oldstr
;
1055 width
+= glyph_width(ch
);
1059 if(prefs
.view_mode
==WIDE
)
1060 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1061 prefs
.encoding
, oldstr
-line_begin
);
1063 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1064 prefs
.encoding
, line_end
-line_begin
);
1068 if (col
!= -1 && line_width
> col
)
1069 #ifdef HAVE_LCD_BITMAP
1070 rb
->lcd_putsxy(left_col
, i
*pf
->height
, utf8_buffer
);
1072 rb
->lcd_puts(left_col
, i
, utf8_buffer
);
1074 if (line_width
> max_line_len
)
1075 max_line_len
= line_width
;
1078 next_line_ptr
= line_end
;
1080 next_screen_ptr
= line_end
;
1081 if (BUFFER_OOB(next_screen_ptr
))
1082 next_screen_ptr
= NULL
;
1084 #ifdef HAVE_LCD_BITMAP
1085 next_screen_to_draw_ptr
= prefs
.page_mode
==OVERLAP
? line_begin
: next_screen_ptr
;
1087 if (prefs
.need_scrollbar
)
1090 next_screen_to_draw_ptr
= next_screen_ptr
;
1097 static void viewer_top(void)
1099 /* Read top of file into buffer
1100 and point screen pointer to top */
1104 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1105 fill_buffer(0, buffer
, buffer_size
);
1108 screen_top_ptr
= buffer
;
1111 static void viewer_bottom(void)
1113 /* Read bottom of file into buffer
1114 and point screen pointer to bottom */
1117 if (file_size
> buffer_size
) {
1118 /* Find last buffer in file, round up to next sector boundary */
1119 last_sectors
= file_size
- buffer_size
+ SMALL_BLOCK_SIZE
;
1120 last_sectors
/= SMALL_BLOCK_SIZE
;
1121 last_sectors
*= SMALL_BLOCK_SIZE
;
1127 if (file_pos
!= last_sectors
)
1129 file_pos
= last_sectors
;
1130 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1131 fill_buffer(last_sectors
, buffer
, buffer_size
);
1134 screen_top_ptr
= buffer_end
-1;
1137 #ifdef HAVE_LCD_BITMAP
1138 static void init_need_scrollbar(void) {
1139 /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
1140 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
1142 prefs
.need_scrollbar
= NEED_SCROLLBAR();
1143 draw_columns
= prefs
.need_scrollbar
? display_columns
-SCROLLBAR_WIDTH
: display_columns
;
1144 par_indent_spaces
= draw_columns
/(5*glyph_width(' '));
1147 #define init_need_scrollbar()
1150 static bool viewer_init(void)
1152 #ifdef HAVE_LCD_BITMAP
1154 pf
= rb
->font_get(FONT_UI
);
1156 display_lines
= LCD_HEIGHT
/ pf
->height
;
1157 draw_columns
= display_columns
= LCD_WIDTH
;
1159 /* REAL fixed pitch :) all chars use up 1 cell */
1161 draw_columns
= display_columns
= 11;
1162 par_indent_spaces
= 2;
1165 fd
= rb
->open(file_name
, O_RDONLY
);
1169 file_size
= rb
->filesize(fd
);
1173 /* Init mac_text value used in processing buffer */
1179 static void viewer_default_settings(void)
1181 prefs
.word_mode
= WRAP
;
1182 prefs
.line_mode
= NORMAL
;
1183 prefs
.view_mode
= NARROW
;
1184 prefs
.scroll_mode
= PAGE
;
1185 #ifdef HAVE_LCD_BITMAP
1186 prefs
.page_mode
= NO_OVERLAP
;
1187 prefs
.scrollbar_mode
= SB_OFF
;
1189 prefs
.autoscroll_speed
= 1;
1190 /* Set codepage to system default */
1191 prefs
.encoding
= rb
->global_settings
->default_codepage
;
1194 static void viewer_load_settings(void) /* same name as global, but not the same file.. */
1197 struct bookmark_file_data
*data
;
1198 struct bookmarked_file_info this_bookmark
;
1200 /* read settings file */
1201 settings_fd
=rb
->open(SETTINGS_FILE
, O_RDONLY
);
1202 if ((settings_fd
>= 0) && (rb
->filesize(settings_fd
) == sizeof(struct preferences
)))
1204 rb
->read(settings_fd
, &prefs
, sizeof(struct preferences
));
1205 rb
->close(settings_fd
);
1209 /* load default settings if there is no settings file */
1210 viewer_default_settings();
1213 rb
->memcpy(&old_prefs
, &prefs
, sizeof(struct preferences
));
1215 data
= (struct bookmark_file_data
*)buffer
; /* grab the text buffer */
1216 data
->bookmarked_files_count
= 0;
1218 /* read bookmarks if file exists */
1219 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_RDONLY
);
1220 if (settings_fd
>= 0)
1222 /* figure out how many items to read */
1223 rb
->read(settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1224 if (data
->bookmarked_files_count
> MAX_BOOKMARKED_FILES
)
1225 data
->bookmarked_files_count
= MAX_BOOKMARKED_FILES
;
1226 rb
->read(settings_fd
, data
->bookmarks
,
1227 sizeof(struct bookmarked_file_info
) * data
->bookmarked_files_count
);
1228 rb
->close(settings_fd
);
1232 screen_top_ptr
= buffer
;
1234 /* check if current file is in list */
1235 for (i
=0; i
< data
->bookmarked_files_count
; i
++)
1237 if (!rb
->strcmp(file_name
, data
->bookmarks
[i
].filename
))
1239 int screen_pos
= data
->bookmarks
[i
].file_position
+ data
->bookmarks
[i
].top_ptr_pos
;
1240 int screen_top
= screen_pos
% buffer_size
;
1241 file_pos
= screen_pos
- screen_top
;
1242 screen_top_ptr
= buffer
+ screen_top
;
1247 this_bookmark
.file_position
= file_pos
;
1248 this_bookmark
.top_ptr_pos
= screen_top_ptr
- buffer
;
1250 rb
->memset(&this_bookmark
.filename
[0],0,MAX_PATH
);
1251 rb
->strcpy(this_bookmark
.filename
,file_name
);
1253 /* prevent potential slot overflow */
1254 if (i
>= data
->bookmarked_files_count
)
1256 if (i
< MAX_BOOKMARKED_FILES
)
1257 data
->bookmarked_files_count
++;
1259 i
= MAX_BOOKMARKED_FILES
-1;
1262 /* write bookmark file with spare slot in first position
1263 to be filled in by viewer_save_settings */
1264 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1265 if (settings_fd
>=0 )
1268 rb
->write (settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1270 /* write the current bookmark */
1271 rb
->write (settings_fd
, &this_bookmark
, sizeof(struct bookmarked_file_info
));
1273 /* write everything that was before this bookmark */
1274 rb
->write (settings_fd
, data
->bookmarks
, sizeof(struct bookmarked_file_info
)*i
);
1276 rb
->close(settings_fd
);
1279 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1281 if (BUFFER_OOB(screen_top_ptr
))
1283 screen_top_ptr
= buffer
;
1286 fill_buffer(file_pos
, buffer
, buffer_size
);
1288 /* remember the current position */
1289 start_position
= file_pos
+ screen_top_ptr
- buffer
;
1291 init_need_scrollbar();
1294 static void viewer_save_settings(void)/* same name as global, but not the same file.. */
1298 /* save the viewer settings if they have been changed */
1299 if (rb
->memcmp(&prefs
, &old_prefs
, sizeof(struct preferences
)))
1301 settings_fd
= rb
->creat(SETTINGS_FILE
); /* create the settings file */
1303 if (settings_fd
>= 0 )
1305 rb
->write (settings_fd
, &prefs
, sizeof(struct preferences
));
1306 rb
->close(settings_fd
);
1310 /* save the bookmark if the position has changed */
1311 if (file_pos
+ screen_top_ptr
- buffer
!= start_position
)
1313 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1315 if (settings_fd
>= 0 )
1317 struct bookmarked_file_info b
;
1318 b
.file_position
= file_pos
+ screen_top_ptr
- buffer
;
1319 b
.top_ptr_pos
= 0; /* this is only kept for legassy reasons */
1320 rb
->memset(&b
.filename
[0],0,MAX_PATH
);
1321 rb
->strcpy(b
.filename
,file_name
);
1322 rb
->lseek(settings_fd
,sizeof(signed int),SEEK_SET
);
1323 rb
->write (settings_fd
, &b
, sizeof(struct bookmarked_file_info
));
1324 rb
->close(settings_fd
);
1329 static void viewer_exit(void *parameter
)
1333 viewer_save_settings();
1337 static int col_limit(int col
)
1342 if (col
> max_line_len
- 2*glyph_width('o'))
1343 col
= max_line_len
- 2*glyph_width('o');
1348 /* settings helper functions */
1350 static bool encoding_setting(void)
1352 static struct opt_items names
[NUM_CODEPAGES
];
1355 for (idx
= 0; idx
< NUM_CODEPAGES
; idx
++)
1357 names
[idx
].string
= rb
->get_codepage_name(idx
);
1358 names
[idx
].voice_id
= -1;
1361 return rb
->set_option("Encoding", &prefs
.encoding
, INT
, names
,
1362 sizeof(names
) / sizeof(names
[0]), NULL
);
1365 static bool word_wrap_setting(void)
1367 static const struct opt_items names
[] = {
1369 {"Off (Chop Words)", -1},
1372 return rb
->set_option("Word Wrap", &prefs
.word_mode
, INT
,
1376 static bool line_mode_setting(void)
1378 static const struct opt_items names
[] = {
1381 {"Expand Lines", -1},
1382 #ifdef HAVE_LCD_BITMAP
1383 {"Reflow Lines", -1},
1387 return rb
->set_option("Line Mode", &prefs
.line_mode
, INT
, names
,
1388 sizeof(names
) / sizeof(names
[0]), NULL
);
1391 static bool view_mode_setting(void)
1393 static const struct opt_items names
[] = {
1394 {"No (Narrow)", -1},
1398 ret
= rb
->set_option("Wide View", &prefs
.view_mode
, INT
,
1400 if (prefs
.view_mode
== NARROW
)
1405 static bool scroll_mode_setting(void)
1407 static const struct opt_items names
[] = {
1408 {"Scroll by Page", -1},
1409 {"Scroll by Line", -1},
1412 return rb
->set_option("Scroll Mode", &prefs
.scroll_mode
, INT
,
1416 #ifdef HAVE_LCD_BITMAP
1417 static bool page_mode_setting(void)
1419 static const struct opt_items names
[] = {
1424 return rb
->set_option("Overlap Pages", &prefs
.page_mode
, INT
,
1428 static bool scrollbar_setting(void)
1430 static const struct opt_items names
[] = {
1435 return rb
->set_option("Show Scrollbar", &prefs
.scrollbar_mode
, INT
,
1440 static bool autoscroll_speed_setting(void)
1442 return rb
->set_int("Auto-scroll Speed", "", UNIT_INT
,
1443 &prefs
.autoscroll_speed
, NULL
, 1, 1, 10, NULL
);
1446 static bool viewer_options_menu(void)
1451 static const struct menu_item items
[] = {
1452 {"Encoding", encoding_setting
},
1453 {"Word Wrap", word_wrap_setting
},
1454 {"Line Mode", line_mode_setting
},
1455 {"Wide View", view_mode_setting
},
1456 #ifdef HAVE_LCD_BITMAP
1457 {"Show Scrollbar", scrollbar_setting
},
1458 {"Overlap Pages", page_mode_setting
},
1460 {"Scroll Mode", scroll_mode_setting
},
1461 {"Auto-Scroll Speed", autoscroll_speed_setting
},
1463 m
= menu_init(items
, sizeof(items
) / sizeof(*items
),
1464 NULL
, NULL
, NULL
, NULL
);
1466 result
= menu_run(m
);
1468 #ifdef HAVE_LCD_BITMAP
1470 /* Show-scrollbar mode for current view-width mode */
1471 init_need_scrollbar();
1476 static void viewer_menu(void)
1480 static const struct menu_item items
[] = {
1482 {"Viewer Options", NULL
},
1483 {"Show Playback Menu", NULL
},
1487 m
= menu_init(items
, sizeof(items
) / sizeof(*items
), NULL
, NULL
, NULL
, NULL
);
1488 result
=menu_show(m
);
1496 case 1: /* change settings */
1497 done
= viewer_options_menu();
1499 case 2: /* playback control */
1500 playback_control(NULL
);
1502 case 3: /* return */
1509 enum plugin_status
plugin_start(const void* file
)
1512 int lastbutton
= BUTTON_NONE
;
1513 bool autoscroll
= false;
1516 old_tick
= *rb
->current_tick
;
1518 /* get the plugin buffer */
1519 buffer
= rb
->plugin_get_buffer((size_t *)&buffer_size
);
1522 return PLUGIN_ERROR
;
1527 rb
->splash(HZ
, "Error opening file.");
1528 return PLUGIN_ERROR
;
1531 viewer_load_settings(); /* load the preferences and bookmark */
1534 rb
->lcd_set_backdrop(NULL
);
1543 if(old_tick
<= *rb
->current_tick
- (110-prefs
.autoscroll_speed
*10))
1545 viewer_scroll_down();
1547 old_tick
= *rb
->current_tick
;
1551 button
= rb
->button_get_w_tmo(HZ
/10);
1557 case VIEWER_AUTOSCROLL
:
1558 #ifdef VIEWER_AUTOSCROLL_PRE
1559 if (lastbutton
!= VIEWER_AUTOSCROLL_PRE
)
1562 autoscroll
= !autoscroll
;
1565 case VIEWER_PAGE_UP
:
1566 case VIEWER_PAGE_UP
| BUTTON_REPEAT
:
1567 if (prefs
.scroll_mode
== PAGE
)
1570 #ifdef HAVE_LCD_BITMAP
1571 for (i
= prefs
.page_mode
==OVERLAP
? 1:0; i
< display_lines
; i
++)
1573 for (i
= 0; i
< display_lines
; i
++)
1579 old_tick
= *rb
->current_tick
;
1583 case VIEWER_PAGE_DOWN
:
1584 case VIEWER_PAGE_DOWN
| BUTTON_REPEAT
:
1585 if (prefs
.scroll_mode
== PAGE
)
1588 if (next_screen_ptr
!= NULL
)
1589 screen_top_ptr
= next_screen_to_draw_ptr
;
1592 viewer_scroll_down();
1593 old_tick
= *rb
->current_tick
;
1597 case VIEWER_SCREEN_LEFT
:
1598 case VIEWER_SCREEN_LEFT
| BUTTON_REPEAT
:
1599 if (prefs
.view_mode
== WIDE
) {
1601 col
-= draw_columns
;
1602 col
= col_limit(col
);
1604 else { /* prefs.view_mode == NARROW */
1612 case VIEWER_SCREEN_RIGHT
:
1613 case VIEWER_SCREEN_RIGHT
| BUTTON_REPEAT
:
1614 if (prefs
.view_mode
== WIDE
) {
1616 col
+= draw_columns
;
1617 col
= col_limit(col
);
1619 else { /* prefs.view_mode == NARROW */
1620 /* Bottom of file */
1627 #ifdef VIEWER_LINE_UP
1628 case VIEWER_LINE_UP
:
1629 case VIEWER_LINE_UP
| BUTTON_REPEAT
:
1630 /* Scroll up one line */
1632 old_tick
= *rb
->current_tick
;
1636 case VIEWER_LINE_DOWN
:
1637 case VIEWER_LINE_DOWN
| BUTTON_REPEAT
:
1638 /* Scroll down one line */
1639 if (next_screen_ptr
!= NULL
)
1640 screen_top_ptr
= next_line_ptr
;
1641 old_tick
= *rb
->current_tick
;
1645 #ifdef VIEWER_COLUMN_LEFT
1646 case VIEWER_COLUMN_LEFT
:
1647 case VIEWER_COLUMN_LEFT
| BUTTON_REPEAT
:
1648 if (prefs
.view_mode
== WIDE
) {
1649 /* Scroll left one column */
1650 col
-= glyph_width('o');
1651 col
= col_limit(col
);
1656 case VIEWER_COLUMN_RIGHT
:
1657 case VIEWER_COLUMN_RIGHT
| BUTTON_REPEAT
:
1658 if (prefs
.view_mode
== WIDE
) {
1659 /* Scroll right one column */
1660 col
+= glyph_width('o');
1661 col
= col_limit(col
);
1667 #ifdef VIEWER_RC_QUIT
1668 case VIEWER_RC_QUIT
:
1676 if (rb
->default_event_handler_ex(button
, viewer_exit
, NULL
)
1677 == SYS_USB_CONNECTED
)
1678 return PLUGIN_USB_CONNECTED
;
1681 if (button
!= BUTTON_NONE
)
1683 lastbutton
= button
;