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 "playback_control.h"
25 #include "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 C200 keys */
189 #elif CONFIG_KEYPAD == SANSA_C200_PAD
190 #define VIEWER_QUIT BUTTON_POWER
191 #define VIEWER_PAGE_UP BUTTON_VOL_UP
192 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
193 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
194 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
195 #define VIEWER_MENU BUTTON_SELECT
196 #define VIEWER_AUTOSCROLL BUTTON_REC
197 #define VIEWER_LINE_UP BUTTON_UP
198 #define VIEWER_LINE_DOWN BUTTON_DOWN
200 /* iriver H10 keys */
201 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
202 #define VIEWER_QUIT BUTTON_POWER
203 #define VIEWER_PAGE_UP BUTTON_SCROLL_UP
204 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_DOWN
205 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
206 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
207 #define VIEWER_MENU BUTTON_REW
208 #define VIEWER_AUTOSCROLL BUTTON_PLAY
211 #elif CONFIG_KEYPAD == MROBE500_PAD
212 #define VIEWER_QUIT BUTTON_POWER
213 #define VIEWER_PAGE_UP BUTTON_RC_PLAY
214 #define VIEWER_PAGE_DOWN BUTTON_RC_DOWN
215 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
216 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
217 #define VIEWER_MENU BUTTON_RC_HEART
218 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
221 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
222 #define VIEWER_QUIT BUTTON_BACK
223 #define VIEWER_PAGE_UP BUTTON_PREV
224 #define VIEWER_PAGE_DOWN BUTTON_NEXT
225 #define VIEWER_SCREEN_LEFT (BUTTON_PLAY | BUTTON_LEFT)
226 #define VIEWER_SCREEN_RIGHT (BUTTON_PLAY | BUTTON_RIGHT)
227 #define VIEWER_MENU BUTTON_MENU
228 #define VIEWER_AUTOSCROLL_PRE BUTTON_PLAY
229 #define VIEWER_AUTOSCROLL (BUTTON_PLAY|BUTTON_REL)
230 #define VIEWER_LINE_UP BUTTON_UP
231 #define VIEWER_LINE_DOWN BUTTON_DOWN
232 #define VIEWER_COLUMN_LEFT BUTTON_LEFT
233 #define VIEWER_COLUMN_RIGHT BUTTON_RIGHT
236 #elif CONFIG_KEYPAD == MROBE100_PAD
237 #define VIEWER_QUIT BUTTON_POWER
238 #define VIEWER_PAGE_UP BUTTON_UP
239 #define VIEWER_PAGE_DOWN BUTTON_DOWN
240 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
241 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
242 #define VIEWER_MENU BUTTON_MENU
243 #define VIEWER_AUTOSCROLL BUTTON_DISPLAY
246 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
247 #define VIEWER_QUIT BUTTON_RC_REC
248 #define VIEWER_PAGE_UP BUTTON_RC_VOL_UP
249 #define VIEWER_PAGE_DOWN BUTTON_RC_VOL_DOWN
250 #define VIEWER_SCREEN_LEFT BUTTON_RC_REW
251 #define VIEWER_SCREEN_RIGHT BUTTON_RC_FF
252 #define VIEWER_MENU BUTTON_RC_MENU
253 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
254 #define VIEWER_RC_QUIT BUTTON_REC
257 #elif CONFIG_KEYPAD == COWOND2_PAD
258 #define VIEWER_QUIT BUTTON_POWER
259 #define VIEWER_MENU BUTTON_MENU
262 #error No keymap defined!
267 #define VIEWER_QUIT BUTTON_TOPLEFT
269 #ifndef VIEWER_PAGE_UP
270 #define VIEWER_PAGE_UP BUTTON_TOPMIDDLE
272 #ifndef VIEWER_PAGE_DOWN
273 #define VIEWER_PAGE_DOWN BUTTON_BOTTOMMIDDLE
275 #ifndef VIEWER_SCREEN_LEFT
276 #define VIEWER_SCREEN_LEFT BUTTON_MIDLEFT
278 #ifndef VIEWER_SCREEN_RIGHT
279 #define VIEWER_SCREEN_RIGHT BUTTON_MIDRIGHT
282 #define VIEWER_MENU BUTTON_TOPRIGHT
284 #ifndef VIEWER_AUTOSCROLL
285 #define VIEWER_AUTOSCROLL BUTTON_CENTER
289 /* stuff for the bookmarking */
290 struct bookmarked_file_info
{
293 char filename
[MAX_PATH
];
296 struct bookmark_file_data
{
297 signed int bookmarked_files_count
;
298 struct bookmarked_file_info bookmarks
[];
311 REFLOW
, /* won't be set on charcell LCD, must be last */
335 } encoding
; /* FIXME: What should default encoding be? */
337 #ifdef HAVE_LCD_BITMAP
348 #endif /* HAVE_LCD_BITMAP */
355 int autoscroll_speed
;
359 struct preferences prefs
;
360 struct preferences old_prefs
;
362 static unsigned char *buffer
;
363 static long buffer_size
;
364 static unsigned char line_break
[] = {0,0x20,9,0xB,0xC,'-'};
365 static int display_columns
; /* number of (pixel) columns on the display */
366 static int display_lines
; /* number of lines on the display */
367 static int draw_columns
; /* number of (pixel) columns available for text */
368 static int par_indent_spaces
; /* number of spaces to indent first paragraph */
370 static const char *file_name
;
371 static long file_size
;
372 static long start_position
; /* position in the file after the viewer is started */
373 static bool mac_text
;
374 static long file_pos
; /* Position of the top of the buffer in the file */
375 static unsigned char *buffer_end
; /*Set to BUFFER_END() when file_pos changes*/
376 static int max_line_len
;
377 static unsigned char *screen_top_ptr
;
378 static unsigned char *next_screen_ptr
;
379 static unsigned char *next_screen_to_draw_ptr
;
380 static unsigned char *next_line_ptr
;
381 static const struct plugin_api
* rb
;
382 #ifdef HAVE_LCD_BITMAP
383 static struct font
*pf
;
387 int glyph_width(int ch
)
392 #ifdef HAVE_LCD_BITMAP
393 return rb
->font_get_width(pf
, ch
);
399 unsigned char* get_ucs(const unsigned char* str
, unsigned short* ch
)
401 unsigned char utf8_tmp
[6];
404 if (prefs
.encoding
== UTF8
)
405 return (unsigned char*)rb
->utf8decode(str
, ch
);
407 count
= BUFFER_OOB(str
+2)? 1:2;
408 rb
->iso_decode(str
, utf8_tmp
, prefs
.encoding
, count
);
409 rb
->utf8decode(utf8_tmp
, ch
);
411 if ((prefs
.encoding
== SJIS
&& *str
> 0xA0 && *str
< 0xE0) || prefs
.encoding
< SJIS
)
412 return (unsigned char*)str
+1;
414 return (unsigned char*)str
+2;
420 #define ADVANCE_COUNTERS(c) { width += glyph_width(c); k++; }
421 #define LINE_IS_FULL ((k>=MAX_COLUMNS-1) ||( width >= draw_columns))
422 #define LINE_IS_NOT_FULL ((k<MAX_COLUMNS-1) &&( width < draw_columns))
423 static unsigned char* crop_at_width(const unsigned char* p
)
427 const unsigned char *oldp
= p
;
431 while (LINE_IS_NOT_FULL
) {
434 ADVANCE_COUNTERS(ch
);
437 return (unsigned char*)oldp
;
440 static unsigned char* find_first_feed(const unsigned char* p
, int size
)
444 for (i
=0; i
< size
; i
++)
446 return (unsigned char*) p
+i
;
451 static unsigned char* find_last_feed(const unsigned char* p
, int size
)
455 for (i
=size
-1; i
>=0; i
--)
457 return (unsigned char*) p
+i
;
462 static unsigned char* find_last_space(const unsigned char* p
, int size
)
466 k
= (prefs
.line_mode
==JOIN
) || (prefs
.line_mode
==REFLOW
) ? 0:1;
468 if (!BUFFER_OOB(&p
[size
]))
469 for (j
=k
; j
< ((int) sizeof(line_break
)) - 1; j
++)
470 if (p
[size
] == line_break
[j
])
471 return (unsigned char*) p
+size
;
473 for (i
=size
-1; i
>=0; i
--)
474 for (j
=k
; j
< (int) sizeof(line_break
); j
++)
476 if (!((p
[i
] == '-') && (prefs
.word_mode
== WRAP
)))
477 if (p
[i
] == line_break
[j
])
478 return (unsigned char*) p
+i
;
484 static unsigned char* find_next_line(const unsigned char* cur_line
, bool *is_short
)
486 const unsigned char *next_line
= NULL
;
487 int size
, i
, j
, k
, width
, search_len
, spaces
, newlines
;
491 if (is_short
!= NULL
)
494 if BUFFER_OOB(cur_line
)
497 if (prefs
.view_mode
== WIDE
) {
498 search_len
= MAX_WIDTH
;
500 else { /* prefs.view_mode == NARROW */
501 search_len
= crop_at_width(cur_line
) - cur_line
;
504 size
= BUFFER_OOB(cur_line
+search_len
) ? buffer_end
-cur_line
: search_len
;
506 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
)) {
507 /* Need to scan ahead and possibly increase search_len and size,
508 or possibly set next_line at second hard return in a row. */
511 for (j
=k
=width
=spaces
=newlines
=0; ; j
++) {
512 if (BUFFER_OOB(cur_line
+j
))
515 size
= search_len
= j
;
522 if (prefs
.line_mode
== REFLOW
) {
525 next_line
= cur_line
+ size
;
526 return (unsigned char*) next_line
;
528 if (j
==0) /* i=1 is intentional */
529 for (i
=0; i
<par_indent_spaces
; i
++)
530 ADVANCE_COUNTERS(' ');
532 if (!first_chars
) spaces
++;
538 next_line
= cur_line
+ size
- spaces
;
539 if (next_line
!= cur_line
)
540 return (unsigned char*) next_line
;
546 if (BUFFER_OOB(cur_line
+size
) || size
> 2*search_len
)
549 spaces
= first_chars
? 0:1;
553 if (prefs
.line_mode
==JOIN
|| newlines
>0) {
556 ADVANCE_COUNTERS(' ');
558 size
= search_len
= j
;
564 /* REFLOW, multiple spaces between words: count only
565 * one. If more are needed, they will be added
569 ADVANCE_COUNTERS(' ');
571 size
= search_len
= j
;
582 /* find first hard return */
583 next_line
= find_first_feed(cur_line
, size
);
586 if (next_line
== NULL
)
587 if (size
== search_len
) {
588 if (prefs
.word_mode
== WRAP
) /* Find last space */
589 next_line
= find_last_space(cur_line
, size
);
591 if (next_line
== NULL
)
592 next_line
= crop_at_width(cur_line
);
594 if (prefs
.word_mode
== WRAP
)
596 i
<WRAP_TRIM
&& isspace(next_line
[0]) && !BUFFER_OOB(next_line
);
601 if (prefs
.line_mode
== EXPAND
)
602 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
603 if (next_line
[0] == 0)
604 if (next_line
!= cur_line
)
605 return (unsigned char*) next_line
;
607 /* If next_line is pointing to a zero, increment it; i.e.,
608 leave the terminator at the end of cur_line. If pointing
609 to a hyphen, increment only if there is room to display
610 the hyphen on current line (won't apply in WIDE mode,
611 since it's guarenteed there won't be room). */
612 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
613 if (next_line
[0] == 0)/* ||
614 (next_line[0] == '-' && next_line-cur_line < draw_columns)) */
617 if (BUFFER_OOB(next_line
))
623 return (unsigned char*) next_line
;
626 static unsigned char* find_prev_line(const unsigned char* cur_line
)
628 const unsigned char *prev_line
= NULL
;
629 const unsigned char *p
;
631 if BUFFER_OOB(cur_line
)
634 /* To wrap consistently at the same places, we must
635 start with a known hard return, then work downwards.
636 We can either search backwards for a hard return,
637 or simply start wrapping downwards from top of buffer.
638 If current line is not near top of buffer, this is
639 a file with long lines (paragraphs). We would need to
640 read earlier sectors before we could decide how to
641 properly wrap the lines above the current line, but
642 it probably is not worth the disk access. Instead,
643 start with top of buffer and wrap down from there.
644 This may result in some lines wrapping at different
645 points from where they wrap when scrolling down.
646 If buffer is at top of file, start at top of buffer. */
648 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
))
649 prev_line
= p
= NULL
;
651 prev_line
= p
= find_last_feed(buffer
, cur_line
-buffer
-1);
652 /* Null means no line feeds in buffer above current line. */
654 if (prev_line
== NULL
)
655 if (BUFFER_BOF() || cur_line
- buffer
> READ_PREV_ZONE
)
656 prev_line
= p
= buffer
;
657 /* (else return NULL and read previous block) */
659 /* Wrap downwards until too far, then use the one before. */
660 while (p
< cur_line
&& p
!= NULL
) {
662 p
= find_next_line(prev_line
, NULL
);
665 if (BUFFER_OOB(prev_line
))
668 return (unsigned char*) prev_line
;
671 static void fill_buffer(long pos
, unsigned char* buf
, unsigned size
)
673 /* Read from file and preprocess the data */
674 /* To minimize disk access, always read on sector boundaries */
676 bool found_CR
= false;
678 rb
->lseek(fd
, pos
, SEEK_SET
);
679 numread
= rb
->read(fd
, buf
, size
);
680 rb
->button_clear_queue(); /* clear button queue */
682 for(i
= 0; i
< numread
; i
++) {
699 case 0: /* No break between case 0 and default, intentionally */
712 static int read_and_synch(int direction
)
714 /* Read next (or prev) block, and reposition global pointers. */
715 /* direction: 1 for down (i.e., further into file), -1 for up */
716 int move_size
, move_vector
, offset
;
717 unsigned char *fill_buf
;
719 if (direction
== -1) /* up */ {
720 move_size
= SMALL_BLOCK_SIZE
;
722 fill_buf
= TOP_SECTOR
;
723 rb
->memcpy(BOTTOM_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
724 rb
->memcpy(MID_SECTOR
, TOP_SECTOR
, SMALL_BLOCK_SIZE
);
727 if (prefs
.view_mode
== WIDE
) {
728 /* WIDE mode needs more buffer so we have to read smaller blocks */
729 move_size
= SMALL_BLOCK_SIZE
;
730 offset
= LARGE_BLOCK_SIZE
;
731 fill_buf
= BOTTOM_SECTOR
;
732 rb
->memcpy(TOP_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
733 rb
->memcpy(MID_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
736 move_size
= LARGE_BLOCK_SIZE
;
737 offset
= SMALL_BLOCK_SIZE
;
738 fill_buf
= MID_SECTOR
;
739 rb
->memcpy(TOP_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
742 move_vector
= direction
* move_size
;
743 screen_top_ptr
-= move_vector
;
744 file_pos
+= move_vector
;
745 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
746 fill_buffer(file_pos
+ offset
, fill_buf
, move_size
);
750 static void viewer_scroll_up(void)
754 p
= find_prev_line(screen_top_ptr
);
755 if (p
== NULL
&& !BUFFER_BOF()) {
757 p
= find_prev_line(screen_top_ptr
);
763 static void viewer_scroll_down(void)
765 if (next_screen_ptr
!= NULL
)
766 screen_top_ptr
= next_line_ptr
;
769 #ifdef HAVE_LCD_BITMAP
770 static void viewer_scrollbar(void) {
771 int items
, min_shown
, max_shown
;
773 items
= (int) file_size
; /* (SH1 int is same as long) */
774 min_shown
= (int) file_pos
+ (screen_top_ptr
- buffer
);
776 if (next_screen_ptr
== NULL
)
779 max_shown
= min_shown
+ (next_screen_ptr
- screen_top_ptr
);
781 rb
->gui_scrollbar_draw(rb
->screens
[SCREEN_MAIN
],0, 0, SCROLLBAR_WIDTH
-1,
782 LCD_HEIGHT
, items
, min_shown
, max_shown
, VERTICAL
);
786 static void viewer_draw(int col
)
788 int i
, j
, k
, line_len
, line_width
, resynch_move
, spaces
, left_col
=0;
789 int width
, extra_spaces
, indent_spaces
, spaces_per_word
;
790 bool multiple_spacing
, line_is_short
;
792 unsigned char *str
, *oldstr
;
793 unsigned char *line_begin
;
794 unsigned char *line_end
;
796 unsigned char scratch_buffer
[MAX_COLUMNS
+ 1];
797 unsigned char utf8_buffer
[MAX_COLUMNS
*4 + 1];
798 unsigned char *endptr
;
800 /* If col==-1 do all calculations but don't display */
802 #ifdef HAVE_LCD_BITMAP
803 left_col
= prefs
.need_scrollbar
? SCROLLBAR_WIDTH
:0;
807 rb
->lcd_clear_display();
810 line_begin
= line_end
= screen_top_ptr
;
812 for (i
= 0; i
< display_lines
; i
++) {
813 if (BUFFER_OOB(line_end
))
814 break; /* Happens after display last line at BUFFER_EOF() */
816 line_begin
= line_end
;
817 line_end
= find_next_line(line_begin
, &line_is_short
);
819 if (line_end
== NULL
) {
821 if (i
< display_lines
- 1 && !BUFFER_BOF()) {
823 rb
->lcd_clear_display();
825 for (; i
< display_lines
- 1; i
++)
828 line_begin
= line_end
= screen_top_ptr
;
833 line_end
= buffer_end
;
837 resynch_move
= read_and_synch(1); /* Read block & move ptrs */
838 line_begin
-= resynch_move
;
840 next_line_ptr
-= resynch_move
;
842 line_end
= find_next_line(line_begin
, NULL
);
843 if (line_end
== NULL
) /* Should not really happen */
847 line_len
= line_end
- line_begin
;
849 /* calculate line_len */
850 str
= oldstr
= line_begin
;
852 while (str
< line_end
) {
854 str
= crop_at_width(str
);
857 line_width
= j
*draw_columns
;
858 while (oldstr
< line_end
) {
859 oldstr
= get_ucs(oldstr
, &ch
);
860 line_width
+= glyph_width(ch
);
863 if (prefs
.line_mode
== JOIN
) {
864 if (line_begin
[0] == 0) {
866 if (prefs
.word_mode
== CHOP
)
871 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
872 if (k
== MAX_COLUMNS
)
882 scratch_buffer
[k
++] = ' ';
887 scratch_buffer
[k
++] = ' ';
888 if (k
== MAX_COLUMNS
- 1)
891 scratch_buffer
[k
++] = c
;
896 scratch_buffer
[k
] = 0;
897 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
898 prefs
.encoding
, draw_columns
/glyph_width('i'));
902 else if (prefs
.line_mode
== REFLOW
) {
903 if (line_begin
[0] == 0) {
905 if (prefs
.word_mode
== CHOP
)
912 if (!line_is_short
) {
913 multiple_spacing
= false;
915 for (str
= line_begin
; str
< line_end
; ) {
916 str
= get_ucs(str
, &ch
);
920 if ((str
== line_begin
) && (prefs
.word_mode
==WRAP
))
921 /* special case: indent the paragraph,
922 * don't count spaces */
923 indent_spaces
= par_indent_spaces
;
924 else if (!multiple_spacing
)
926 multiple_spacing
= true;
929 multiple_spacing
= false;
930 width
+= glyph_width(ch
);
934 if (multiple_spacing
) spaces
--;
937 /* total number of spaces to insert between words */
938 extra_spaces
= (draw_columns
-width
)/glyph_width(' ')
940 /* number of spaces between each word*/
941 spaces_per_word
= extra_spaces
/ spaces
;
942 /* number of words with n+1 spaces (to fill up) */
943 extra_spaces
= extra_spaces
% spaces
;
944 if (spaces_per_word
> 2) { /* too much spacing is awful */
948 } else { /* this doesn't matter much... no spaces anyway */
949 spaces_per_word
= extra_spaces
= 0;
951 } else { /* end of a paragraph: don't fill line */
956 multiple_spacing
= false;
957 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
958 if (k
== MAX_COLUMNS
)
965 if (j
==0 && prefs
.word_mode
==WRAP
) { /* indent paragraph */
966 for (j
=0; j
<par_indent_spaces
; j
++)
967 scratch_buffer
[k
++] = ' ';
970 else if (!multiple_spacing
) {
971 for (width
= spaces
<extra_spaces
? -1:0; width
< spaces_per_word
; width
++)
972 scratch_buffer
[k
++] = ' ';
975 multiple_spacing
= true;
978 scratch_buffer
[k
++] = c
;
979 multiple_spacing
= false;
985 scratch_buffer
[k
] = 0;
986 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
987 prefs
.encoding
, k
-col
);
991 else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */
993 if (line_width
> col
) {
994 str
= oldstr
= line_begin
;
997 while( (width
<draw_columns
) && (oldstr
<line_end
) )
999 oldstr
= get_ucs(oldstr
, &ch
);
1001 k
-= glyph_width(ch
);
1002 line_begin
= oldstr
;
1004 width
+= glyph_width(ch
);
1008 if(prefs
.view_mode
==WIDE
)
1009 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1010 prefs
.encoding
, oldstr
-line_begin
);
1012 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1013 prefs
.encoding
, line_end
-line_begin
);
1017 if (col
!= -1 && line_width
> col
)
1018 #ifdef HAVE_LCD_BITMAP
1019 rb
->lcd_putsxy(left_col
, i
*pf
->height
, utf8_buffer
);
1021 rb
->lcd_puts(left_col
, i
, utf8_buffer
);
1023 if (line_width
> max_line_len
)
1024 max_line_len
= line_width
;
1027 next_line_ptr
= line_end
;
1029 next_screen_ptr
= line_end
;
1030 if (BUFFER_OOB(next_screen_ptr
))
1031 next_screen_ptr
= NULL
;
1033 #ifdef HAVE_LCD_BITMAP
1034 next_screen_to_draw_ptr
= prefs
.page_mode
==OVERLAP
? line_begin
: next_screen_ptr
;
1036 if (prefs
.need_scrollbar
)
1039 next_screen_to_draw_ptr
= next_screen_ptr
;
1046 static void viewer_top(void)
1048 /* Read top of file into buffer
1049 and point screen pointer to top */
1053 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1054 fill_buffer(0, buffer
, buffer_size
);
1057 screen_top_ptr
= buffer
;
1060 static void viewer_bottom(void)
1062 /* Read bottom of file into buffer
1063 and point screen pointer to bottom */
1066 if (file_size
> buffer_size
) {
1067 /* Find last buffer in file, round up to next sector boundary */
1068 last_sectors
= file_size
- buffer_size
+ SMALL_BLOCK_SIZE
;
1069 last_sectors
/= SMALL_BLOCK_SIZE
;
1070 last_sectors
*= SMALL_BLOCK_SIZE
;
1076 if (file_pos
!= last_sectors
)
1078 file_pos
= last_sectors
;
1079 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1080 fill_buffer(last_sectors
, buffer
, buffer_size
);
1083 screen_top_ptr
= buffer_end
-1;
1086 #ifdef HAVE_LCD_BITMAP
1087 static void init_need_scrollbar(void) {
1088 /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
1089 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
1091 prefs
.need_scrollbar
= NEED_SCROLLBAR();
1092 draw_columns
= prefs
.need_scrollbar
? display_columns
-SCROLLBAR_WIDTH
: display_columns
;
1093 par_indent_spaces
= draw_columns
/(5*glyph_width(' '));
1096 #define init_need_scrollbar()
1099 static bool viewer_init(void)
1101 #ifdef HAVE_LCD_BITMAP
1103 pf
= rb
->font_get(FONT_UI
);
1105 display_lines
= LCD_HEIGHT
/ pf
->height
;
1106 draw_columns
= display_columns
= LCD_WIDTH
;
1108 /* REAL fixed pitch :) all chars use up 1 cell */
1110 draw_columns
= display_columns
= 11;
1111 par_indent_spaces
= 2;
1114 fd
= rb
->open(file_name
, O_RDONLY
);
1118 file_size
= rb
->filesize(fd
);
1122 /* Init mac_text value used in processing buffer */
1128 static void viewer_default_settings(void)
1130 prefs
.word_mode
= WRAP
;
1131 prefs
.line_mode
= NORMAL
;
1132 prefs
.view_mode
= NARROW
;
1133 prefs
.scroll_mode
= PAGE
;
1134 #ifdef HAVE_LCD_BITMAP
1135 prefs
.page_mode
= NO_OVERLAP
;
1136 prefs
.scrollbar_mode
= SB_OFF
;
1138 prefs
.autoscroll_speed
= 1;
1139 /* Set codepage to system default */
1140 prefs
.encoding
= rb
->global_settings
->default_codepage
;
1143 static void viewer_load_settings(void) /* same name as global, but not the same file.. */
1146 struct bookmark_file_data
*data
;
1147 struct bookmarked_file_info this_bookmark
;
1149 /* read settings file */
1150 settings_fd
=rb
->open(SETTINGS_FILE
, O_RDONLY
);
1151 if ((settings_fd
>= 0) && (rb
->filesize(settings_fd
) == sizeof(struct preferences
)))
1153 rb
->read(settings_fd
, &prefs
, sizeof(struct preferences
));
1154 rb
->close(settings_fd
);
1158 /* load default settings if there is no settings file */
1159 viewer_default_settings();
1162 rb
->memcpy(&old_prefs
, &prefs
, sizeof(struct preferences
));
1164 data
= (struct bookmark_file_data
*)buffer
; /* grab the text buffer */
1165 data
->bookmarked_files_count
= 0;
1167 /* read bookmarks if file exists */
1168 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_RDONLY
);
1169 if (settings_fd
>= 0)
1171 /* figure out how many items to read */
1172 rb
->read(settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1173 if (data
->bookmarked_files_count
> MAX_BOOKMARKED_FILES
)
1174 data
->bookmarked_files_count
= MAX_BOOKMARKED_FILES
;
1175 rb
->read(settings_fd
, data
->bookmarks
,
1176 sizeof(struct bookmarked_file_info
) * data
->bookmarked_files_count
);
1177 rb
->close(settings_fd
);
1181 screen_top_ptr
= buffer
;
1183 /* check if current file is in list */
1184 for (i
=0; i
< data
->bookmarked_files_count
; i
++)
1186 if (!rb
->strcmp(file_name
, data
->bookmarks
[i
].filename
))
1188 int screen_pos
= data
->bookmarks
[i
].file_position
+ data
->bookmarks
[i
].top_ptr_pos
;
1189 int screen_top
= screen_pos
% buffer_size
;
1190 file_pos
= screen_pos
- screen_top
;
1191 screen_top_ptr
= buffer
+ screen_top
;
1196 this_bookmark
.file_position
= file_pos
;
1197 this_bookmark
.top_ptr_pos
= screen_top_ptr
- buffer
;
1199 rb
->memset(&this_bookmark
.filename
[0],0,MAX_PATH
);
1200 rb
->strcpy(this_bookmark
.filename
,file_name
);
1202 /* prevent potential slot overflow */
1203 if (i
>= data
->bookmarked_files_count
)
1205 if (i
< MAX_BOOKMARKED_FILES
)
1206 data
->bookmarked_files_count
++;
1208 i
= MAX_BOOKMARKED_FILES
-1;
1211 /* write bookmark file with spare slot in first position
1212 to be filled in by viewer_save_settings */
1213 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1214 if (settings_fd
>=0 )
1217 rb
->write (settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1219 /* write the current bookmark */
1220 rb
->write (settings_fd
, &this_bookmark
, sizeof(struct bookmarked_file_info
));
1222 /* write everything that was before this bookmark */
1223 rb
->write (settings_fd
, data
->bookmarks
, sizeof(struct bookmarked_file_info
)*i
);
1225 rb
->close(settings_fd
);
1228 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1230 if (BUFFER_OOB(screen_top_ptr
))
1232 screen_top_ptr
= buffer
;
1235 fill_buffer(file_pos
, buffer
, buffer_size
);
1237 /* remember the current position */
1238 start_position
= file_pos
+ screen_top_ptr
- buffer
;
1240 init_need_scrollbar();
1243 static void viewer_save_settings(void)/* same name as global, but not the same file.. */
1247 /* save the viewer settings if they have been changed */
1248 if (rb
->memcmp(&prefs
, &old_prefs
, sizeof(struct preferences
)))
1250 settings_fd
= rb
->creat(SETTINGS_FILE
); /* create the settings file */
1252 if (settings_fd
>= 0 )
1254 rb
->write (settings_fd
, &prefs
, sizeof(struct preferences
));
1255 rb
->close(settings_fd
);
1259 /* save the bookmark if the position has changed */
1260 if (file_pos
+ screen_top_ptr
- buffer
!= start_position
)
1262 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1264 if (settings_fd
>= 0 )
1266 struct bookmarked_file_info b
;
1267 b
.file_position
= file_pos
+ screen_top_ptr
- buffer
;
1268 b
.top_ptr_pos
= 0; /* this is only kept for legassy reasons */
1269 rb
->memset(&b
.filename
[0],0,MAX_PATH
);
1270 rb
->strcpy(b
.filename
,file_name
);
1271 rb
->PREFIX(lseek
)(settings_fd
,sizeof(signed int),SEEK_SET
);
1272 rb
->write (settings_fd
, &b
, sizeof(struct bookmarked_file_info
));
1273 rb
->close(settings_fd
);
1278 static void viewer_exit(void *parameter
)
1282 viewer_save_settings();
1286 static int col_limit(int col
)
1291 if (col
> max_line_len
- 2*glyph_width('o'))
1292 col
= max_line_len
- 2*glyph_width('o');
1297 /* settings helper functions */
1299 static bool encoding_setting(void)
1301 static const struct opt_items names
[] = {
1306 {"ISO-8859-11", -1},
1318 return rb
->set_option("Encoding", &prefs
.encoding
, INT
, names
,
1319 sizeof(names
) / sizeof(names
[0]), NULL
);
1322 static bool word_wrap_setting(void)
1324 static const struct opt_items names
[] = {
1326 {"Off (Chop Words)", -1},
1329 return rb
->set_option("Word Wrap", &prefs
.word_mode
, INT
,
1333 static bool line_mode_setting(void)
1335 static const struct opt_items names
[] = {
1338 {"Expand Lines", -1},
1339 #ifdef HAVE_LCD_BITMAP
1340 {"Reflow Lines", -1},
1344 return rb
->set_option("Line Mode", &prefs
.line_mode
, INT
, names
,
1345 sizeof(names
) / sizeof(names
[0]), NULL
);
1348 static bool view_mode_setting(void)
1350 static const struct opt_items names
[] = {
1351 {"No (Narrow)", -1},
1355 ret
= rb
->set_option("Wide View", &prefs
.view_mode
, INT
,
1357 if (prefs
.view_mode
== NARROW
)
1362 static bool scroll_mode_setting(void)
1364 static const struct opt_items names
[] = {
1365 {"Scroll by Page", -1},
1366 {"Scroll by Line", -1},
1369 return rb
->set_option("Scroll Mode", &prefs
.scroll_mode
, INT
,
1373 #ifdef HAVE_LCD_BITMAP
1374 static bool page_mode_setting(void)
1376 static const struct opt_items names
[] = {
1381 return rb
->set_option("Overlap Pages", &prefs
.page_mode
, INT
,
1385 static bool scrollbar_setting(void)
1387 static const struct opt_items names
[] = {
1392 return rb
->set_option("Show Scrollbar", &prefs
.scrollbar_mode
, INT
,
1397 static bool autoscroll_speed_setting(void)
1399 return rb
->set_int("Auto-scroll Speed", "", UNIT_INT
,
1400 &prefs
.autoscroll_speed
, NULL
, 1, 1, 10, NULL
);
1403 static bool viewer_options_menu(void)
1408 static const struct menu_item items
[] = {
1409 {"Encoding", encoding_setting
},
1410 {"Word Wrap", word_wrap_setting
},
1411 {"Line Mode", line_mode_setting
},
1412 {"Wide View", view_mode_setting
},
1413 #ifdef HAVE_LCD_BITMAP
1414 {"Show Scrollbar", scrollbar_setting
},
1415 {"Overlap Pages", page_mode_setting
},
1417 {"Scroll Mode", scroll_mode_setting
},
1418 {"Auto-Scroll Speed", autoscroll_speed_setting
},
1420 m
= menu_init(rb
, items
, sizeof(items
) / sizeof(*items
),
1421 NULL
, NULL
, NULL
, NULL
);
1423 result
= menu_run(m
);
1425 #ifdef HAVE_LCD_BITMAP
1427 /* Show-scrollbar mode for current view-width mode */
1428 init_need_scrollbar();
1433 static void viewer_menu(void)
1437 static const struct menu_item items
[] = {
1439 {"Viewer Options", NULL
},
1440 {"Show Playback Menu", NULL
},
1444 m
= menu_init(rb
, items
, sizeof(items
) / sizeof(*items
), NULL
, NULL
, NULL
, NULL
);
1445 result
=menu_show(m
);
1453 case 1: /* change settings */
1454 done
= viewer_options_menu();
1456 case 2: /* playback control */
1457 playback_control(rb
, NULL
);
1459 case 3: /* return */
1466 enum plugin_status
plugin_start(const struct plugin_api
* api
, const void* file
)
1469 int lastbutton
= BUTTON_NONE
;
1470 bool autoscroll
= false;
1474 old_tick
= *rb
->current_tick
;
1476 /* get the plugin buffer */
1477 buffer
= rb
->plugin_get_buffer((size_t *)&buffer_size
);
1480 return PLUGIN_ERROR
;
1485 rb
->splash(HZ
, "Error opening file.");
1486 return PLUGIN_ERROR
;
1489 viewer_load_settings(); /* load the preferences and bookmark */
1492 rb
->lcd_set_backdrop(NULL
);
1501 if(old_tick
<= *rb
->current_tick
- (110-prefs
.autoscroll_speed
*10))
1503 viewer_scroll_down();
1505 old_tick
= *rb
->current_tick
;
1509 button
= rb
->button_get_w_tmo(HZ
/10);
1515 case VIEWER_AUTOSCROLL
:
1516 #ifdef VIEWER_AUTOSCROLL_PRE
1517 if (lastbutton
!= VIEWER_AUTOSCROLL_PRE
)
1520 autoscroll
= !autoscroll
;
1523 case VIEWER_PAGE_UP
:
1524 case VIEWER_PAGE_UP
| BUTTON_REPEAT
:
1525 if (prefs
.scroll_mode
== PAGE
)
1528 #ifdef HAVE_LCD_BITMAP
1529 for (i
= prefs
.page_mode
==OVERLAP
? 1:0; i
< display_lines
; i
++)
1531 for (i
= 0; i
< display_lines
; i
++)
1537 old_tick
= *rb
->current_tick
;
1541 case VIEWER_PAGE_DOWN
:
1542 case VIEWER_PAGE_DOWN
| BUTTON_REPEAT
:
1543 if (prefs
.scroll_mode
== PAGE
)
1546 if (next_screen_ptr
!= NULL
)
1547 screen_top_ptr
= next_screen_to_draw_ptr
;
1550 viewer_scroll_down();
1551 old_tick
= *rb
->current_tick
;
1555 case VIEWER_SCREEN_LEFT
:
1556 case VIEWER_SCREEN_LEFT
| BUTTON_REPEAT
:
1557 if (prefs
.view_mode
== WIDE
) {
1559 col
-= draw_columns
;
1560 col
= col_limit(col
);
1562 else { /* prefs.view_mode == NARROW */
1570 case VIEWER_SCREEN_RIGHT
:
1571 case VIEWER_SCREEN_RIGHT
| BUTTON_REPEAT
:
1572 if (prefs
.view_mode
== WIDE
) {
1574 col
+= draw_columns
;
1575 col
= col_limit(col
);
1577 else { /* prefs.view_mode == NARROW */
1578 /* Bottom of file */
1585 #ifdef VIEWER_LINE_UP
1586 case VIEWER_LINE_UP
:
1587 case VIEWER_LINE_UP
| BUTTON_REPEAT
:
1588 /* Scroll up one line */
1590 old_tick
= *rb
->current_tick
;
1594 case VIEWER_LINE_DOWN
:
1595 case VIEWER_LINE_DOWN
| BUTTON_REPEAT
:
1596 /* Scroll down one line */
1597 if (next_screen_ptr
!= NULL
)
1598 screen_top_ptr
= next_line_ptr
;
1599 old_tick
= *rb
->current_tick
;
1603 #ifdef VIEWER_COLUMN_LEFT
1604 case VIEWER_COLUMN_LEFT
:
1605 case VIEWER_COLUMN_LEFT
| BUTTON_REPEAT
:
1606 if (prefs
.view_mode
== WIDE
) {
1607 /* Scroll left one column */
1608 col
-= glyph_width('o');
1609 col
= col_limit(col
);
1614 case VIEWER_COLUMN_RIGHT
:
1615 case VIEWER_COLUMN_RIGHT
| BUTTON_REPEAT
:
1616 if (prefs
.view_mode
== WIDE
) {
1617 /* Scroll right one column */
1618 col
+= glyph_width('o');
1619 col
= col_limit(col
);
1625 #ifdef VIEWER_RC_QUIT
1626 case VIEWER_RC_QUIT
:
1634 if (rb
->default_event_handler_ex(button
, viewer_exit
, NULL
)
1635 == SYS_USB_CONNECTED
)
1636 return PLUGIN_USB_CONNECTED
;
1639 if (button
!= BUTTON_NONE
)
1641 lastbutton
= button
;