1 /***************************************************************************
4 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
11 * Copyright (C) 2002 Gilles Roux, 2003 Garrett Derner
13 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
19 ****************************************************************************/
22 #include "playback_control.h"
23 #include "oldmenuapi.h"
27 #define SETTINGS_FILE VIEWERS_DIR "/viewer.dat" /* binary file, so dont use .cfg */
28 #define BOOKMARKS_FILE VIEWERS_DIR "/viewer_bookmarks.dat"
30 #define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */
31 #define MAX_COLUMNS 64 /* Max displayable string len (over-estimate) */
32 #define MAX_WIDTH 910 /* Max line length in WIDE mode */
33 #define READ_PREV_ZONE 910 /* Arbitrary number less than SMALL_BLOCK_SIZE */
34 #define SMALL_BLOCK_SIZE 0x1000 /* 4k: Smallest file chunk we will read */
35 #define LARGE_BLOCK_SIZE 0x2000 /* 8k: Preferable size of file chunk to read */
36 #define TOP_SECTOR buffer
37 #define MID_SECTOR (buffer + SMALL_BLOCK_SIZE)
38 #define BOTTOM_SECTOR (buffer + 2*(SMALL_BLOCK_SIZE))
39 #define SCROLLBAR_WIDTH 6
41 #define MAX_BOOKMARKED_FILES ((buffer_size/(signed)sizeof(struct bookmarked_file_info))-1)
43 /* Out-Of-Bounds test for any pointer to data in the buffer */
44 #define BUFFER_OOB(p) ((p) < buffer || (p) >= buffer_end)
46 /* Does the buffer contain the beginning of the file? */
47 #define BUFFER_BOF() (file_pos==0)
49 /* Does the buffer contain the end of the file? */
50 #define BUFFER_EOF() (file_size-file_pos <= buffer_size)
52 /* Formula for the endpoint address outside of buffer data */
53 #define BUFFER_END() \
54 ((BUFFER_EOF()) ? (file_size-file_pos+buffer) : (buffer+buffer_size))
56 /* Is the entire file being shown in one screen? */
57 #define ONE_SCREEN_FITS_ALL() \
58 (next_screen_ptr==NULL && screen_top_ptr==buffer && BUFFER_BOF())
60 /* Is a scrollbar called for on the current screen? */
61 #define NEED_SCROLLBAR() \
62 ((!(ONE_SCREEN_FITS_ALL())) && (prefs.scrollbar_mode==SB_ON))
64 /* variable button definitions */
67 #if CONFIG_KEYPAD == RECORDER_PAD
68 #define VIEWER_QUIT BUTTON_OFF
69 #define VIEWER_PAGE_UP BUTTON_UP
70 #define VIEWER_PAGE_DOWN BUTTON_DOWN
71 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
72 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
73 #define VIEWER_MENU BUTTON_F1
74 #define VIEWER_AUTOSCROLL BUTTON_PLAY
75 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
76 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
77 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
78 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
80 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
81 #define VIEWER_QUIT BUTTON_OFF
82 #define VIEWER_PAGE_UP BUTTON_UP
83 #define VIEWER_PAGE_DOWN BUTTON_DOWN
84 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
85 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
86 #define VIEWER_MENU BUTTON_F1
87 #define VIEWER_AUTOSCROLL BUTTON_SELECT
88 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
89 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
90 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
91 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
94 #elif CONFIG_KEYPAD == ONDIO_PAD
95 #define VIEWER_QUIT BUTTON_OFF
96 #define VIEWER_PAGE_UP BUTTON_UP
97 #define VIEWER_PAGE_DOWN BUTTON_DOWN
98 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
99 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
100 #define VIEWER_MENU (BUTTON_MENU|BUTTON_REPEAT)
101 #define VIEWER_AUTOSCROLL_PRE BUTTON_MENU
102 #define VIEWER_AUTOSCROLL (BUTTON_MENU|BUTTON_REL)
105 #elif CONFIG_KEYPAD == PLAYER_PAD
106 #define VIEWER_QUIT BUTTON_STOP
107 #define VIEWER_PAGE_UP BUTTON_LEFT
108 #define VIEWER_PAGE_DOWN BUTTON_RIGHT
109 #define VIEWER_SCREEN_LEFT (BUTTON_ON|BUTTON_LEFT)
110 #define VIEWER_SCREEN_RIGHT (BUTTON_ON|BUTTON_RIGHT)
111 #define VIEWER_MENU BUTTON_MENU
112 #define VIEWER_AUTOSCROLL BUTTON_PLAY
114 /* iRiver H1x0 && H3x0 keys */
115 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
116 (CONFIG_KEYPAD == IRIVER_H300_PAD)
117 #define VIEWER_QUIT BUTTON_OFF
118 #define VIEWER_PAGE_UP BUTTON_UP
119 #define VIEWER_PAGE_DOWN BUTTON_DOWN
120 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
121 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
122 #define VIEWER_MENU BUTTON_MODE
123 #define VIEWER_AUTOSCROLL BUTTON_SELECT
124 #define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP)
125 #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN)
126 #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT)
127 #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT)
129 #define VIEWER_RC_QUIT BUTTON_RC_STOP
132 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
133 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
134 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
135 #define VIEWER_QUIT_PRE BUTTON_SELECT
136 #define VIEWER_QUIT (BUTTON_SELECT | BUTTON_MENU)
137 #define VIEWER_PAGE_UP BUTTON_SCROLL_BACK
138 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_FWD
139 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
140 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
141 #define VIEWER_MENU BUTTON_MENU
142 #define VIEWER_AUTOSCROLL BUTTON_PLAY
145 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
146 #define VIEWER_QUIT BUTTON_PLAY
147 #define VIEWER_PAGE_UP BUTTON_UP
148 #define VIEWER_PAGE_DOWN BUTTON_DOWN
149 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
150 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
151 #define VIEWER_MENU BUTTON_MODE
152 #define VIEWER_AUTOSCROLL BUTTON_SELECT
155 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
156 #define VIEWER_QUIT BUTTON_POWER
157 #define VIEWER_PAGE_UP BUTTON_UP
158 #define VIEWER_PAGE_DOWN BUTTON_DOWN
159 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
160 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
161 #define VIEWER_MENU BUTTON_SELECT
162 #define VIEWER_AUTOSCROLL BUTTON_PLAY
165 #elif CONFIG_KEYPAD == GIGABEAT_PAD
166 #define VIEWER_QUIT BUTTON_POWER
167 #define VIEWER_PAGE_UP BUTTON_UP
168 #define VIEWER_PAGE_DOWN BUTTON_DOWN
169 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
170 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
171 #define VIEWER_MENU BUTTON_MENU
172 #define VIEWER_AUTOSCROLL BUTTON_A
174 /* Sansa E200 keys */
175 #elif CONFIG_KEYPAD == SANSA_E200_PAD
176 #define VIEWER_QUIT BUTTON_POWER
177 #define VIEWER_PAGE_UP BUTTON_UP
178 #define VIEWER_PAGE_DOWN BUTTON_DOWN
179 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
180 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
181 #define VIEWER_MENU BUTTON_SELECT
182 #define VIEWER_AUTOSCROLL BUTTON_REC
183 #define VIEWER_LINE_UP BUTTON_SCROLL_BACK
184 #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD
186 /* Sansa C200 keys */
187 #elif CONFIG_KEYPAD == SANSA_C200_PAD
188 #define VIEWER_QUIT BUTTON_POWER
189 #define VIEWER_PAGE_UP BUTTON_VOL_UP
190 #define VIEWER_PAGE_DOWN BUTTON_VOL_DOWN
191 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
192 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
193 #define VIEWER_MENU BUTTON_SELECT
194 #define VIEWER_AUTOSCROLL BUTTON_REC
195 #define VIEWER_LINE_UP BUTTON_UP
196 #define VIEWER_LINE_DOWN BUTTON_DOWN
198 /* iriver H10 keys */
199 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
200 #define VIEWER_QUIT BUTTON_POWER
201 #define VIEWER_PAGE_UP BUTTON_SCROLL_UP
202 #define VIEWER_PAGE_DOWN BUTTON_SCROLL_DOWN
203 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
204 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
205 #define VIEWER_MENU BUTTON_REW
206 #define VIEWER_AUTOSCROLL BUTTON_PLAY
209 #elif CONFIG_KEYPAD == MROBE500_PAD
210 #define VIEWER_QUIT BUTTON_POWER
211 #define VIEWER_PAGE_UP BUTTON_RC_PLAY
212 #define VIEWER_PAGE_DOWN BUTTON_RC_DOWN
213 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
214 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
215 #define VIEWER_MENU BUTTON_RC_HEART
216 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
219 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
220 #define VIEWER_QUIT BUTTON_BACK
221 #define VIEWER_PAGE_UP BUTTON_PREV
222 #define VIEWER_PAGE_DOWN BUTTON_NEXT
223 #define VIEWER_SCREEN_LEFT (BUTTON_PLAY | BUTTON_LEFT)
224 #define VIEWER_SCREEN_RIGHT (BUTTON_PLAY | BUTTON_RIGHT)
225 #define VIEWER_MENU BUTTON_MENU
226 #define VIEWER_AUTOSCROLL_PRE BUTTON_PLAY
227 #define VIEWER_AUTOSCROLL (BUTTON_PLAY|BUTTON_REL)
228 #define VIEWER_LINE_UP BUTTON_UP
229 #define VIEWER_LINE_DOWN BUTTON_DOWN
230 #define VIEWER_COLUMN_LEFT BUTTON_LEFT
231 #define VIEWER_COLUMN_RIGHT BUTTON_RIGHT
234 #elif CONFIG_KEYPAD == MROBE100_PAD
235 #define VIEWER_QUIT BUTTON_POWER
236 #define VIEWER_PAGE_UP BUTTON_UP
237 #define VIEWER_PAGE_DOWN BUTTON_DOWN
238 #define VIEWER_SCREEN_LEFT BUTTON_LEFT
239 #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT
240 #define VIEWER_MENU BUTTON_MENU
241 #define VIEWER_AUTOSCROLL BUTTON_DISPLAY
244 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
245 #define VIEWER_QUIT BUTTON_RC_REC
246 #define VIEWER_PAGE_UP BUTTON_RC_VOL_UP
247 #define VIEWER_PAGE_DOWN BUTTON_RC_VOL_DOWN
248 #define VIEWER_SCREEN_LEFT BUTTON_RC_REW
249 #define VIEWER_SCREEN_RIGHT BUTTON_RC_FF
250 #define VIEWER_MENU BUTTON_RC_MENU
251 #define VIEWER_AUTOSCROLL BUTTON_RC_MODE
252 #define VIEWER_RC_QUIT BUTTON_REC
255 #elif CONFIG_KEYPAD == COWOND2_PAD
256 #define VIEWER_QUIT BUTTON_POWER
257 #define VIEWER_MENU BUTTON_MENU
260 #error No keymap defined!
265 #define VIEWER_QUIT BUTTON_TOPLEFT
267 #ifndef VIEWER_PAGE_UP
268 #define VIEWER_PAGE_UP BUTTON_TOPMIDDLE
270 #ifndef VIEWER_PAGE_DOWN
271 #define VIEWER_PAGE_DOWN BUTTON_BOTTOMMIDDLE
273 #ifndef VIEWER_SCREEN_LEFT
274 #define VIEWER_SCREEN_LEFT BUTTON_MIDLEFT
276 #ifndef VIEWER_SCREEN_RIGHT
277 #define VIEWER_SCREEN_RIGHT BUTTON_MIDRIGHT
280 #define VIEWER_MENU BUTTON_TOPRIGHT
282 #ifndef VIEWER_AUTOSCROLL
283 #define VIEWER_AUTOSCROLL BUTTON_CENTER
287 /* stuff for the bookmarking */
288 struct bookmarked_file_info
{
291 char filename
[MAX_PATH
];
294 struct bookmark_file_data
{
295 signed int bookmarked_files_count
;
296 struct bookmarked_file_info bookmarks
[];
309 REFLOW
, /* won't be set on charcell LCD, must be last */
333 } encoding
; /* FIXME: What should default encoding be? */
335 #ifdef HAVE_LCD_BITMAP
346 #endif /* HAVE_LCD_BITMAP */
353 int autoscroll_speed
;
357 struct preferences prefs
;
358 struct preferences old_prefs
;
360 static unsigned char *buffer
;
361 static long buffer_size
;
362 static unsigned char line_break
[] = {0,0x20,9,0xB,0xC,'-'};
363 static int display_columns
; /* number of (pixel) columns on the display */
364 static int display_lines
; /* number of lines on the display */
365 static int draw_columns
; /* number of (pixel) columns available for text */
366 static int par_indent_spaces
; /* number of spaces to indent first paragraph */
368 static const char *file_name
;
369 static long file_size
;
370 static long start_position
; /* position in the file after the viewer is started */
371 static bool mac_text
;
372 static long file_pos
; /* Position of the top of the buffer in the file */
373 static unsigned char *buffer_end
; /*Set to BUFFER_END() when file_pos changes*/
374 static int max_line_len
;
375 static unsigned char *screen_top_ptr
;
376 static unsigned char *next_screen_ptr
;
377 static unsigned char *next_screen_to_draw_ptr
;
378 static unsigned char *next_line_ptr
;
379 static const struct plugin_api
* rb
;
380 #ifdef HAVE_LCD_BITMAP
381 static struct font
*pf
;
385 int glyph_width(int ch
)
390 #ifdef HAVE_LCD_BITMAP
391 return rb
->font_get_width(pf
, ch
);
397 unsigned char* get_ucs(const unsigned char* str
, unsigned short* ch
)
399 unsigned char utf8_tmp
[6];
402 if (prefs
.encoding
== UTF8
)
403 return (unsigned char*)rb
->utf8decode(str
, ch
);
405 count
= BUFFER_OOB(str
+2)? 1:2;
406 rb
->iso_decode(str
, utf8_tmp
, prefs
.encoding
, count
);
407 rb
->utf8decode(utf8_tmp
, ch
);
409 if ((prefs
.encoding
== SJIS
&& *str
> 0xA0 && *str
< 0xE0) || prefs
.encoding
< SJIS
)
410 return (unsigned char*)str
+1;
412 return (unsigned char*)str
+2;
418 #define ADVANCE_COUNTERS(c) { width += glyph_width(c); k++; }
419 #define LINE_IS_FULL ((k>=MAX_COLUMNS-1) ||( width >= draw_columns))
420 #define LINE_IS_NOT_FULL ((k<MAX_COLUMNS-1) &&( width < draw_columns))
421 static unsigned char* crop_at_width(const unsigned char* p
)
425 const unsigned char *oldp
= p
;
429 while (LINE_IS_NOT_FULL
) {
432 ADVANCE_COUNTERS(ch
);
435 return (unsigned char*)oldp
;
438 static unsigned char* find_first_feed(const unsigned char* p
, int size
)
442 for (i
=0; i
< size
; i
++)
444 return (unsigned char*) p
+i
;
449 static unsigned char* find_last_feed(const unsigned char* p
, int size
)
453 for (i
=size
-1; i
>=0; i
--)
455 return (unsigned char*) p
+i
;
460 static unsigned char* find_last_space(const unsigned char* p
, int size
)
464 k
= (prefs
.line_mode
==JOIN
) || (prefs
.line_mode
==REFLOW
) ? 0:1;
466 if (!BUFFER_OOB(&p
[size
]))
467 for (j
=k
; j
< ((int) sizeof(line_break
)) - 1; j
++)
468 if (p
[size
] == line_break
[j
])
469 return (unsigned char*) p
+size
;
471 for (i
=size
-1; i
>=0; i
--)
472 for (j
=k
; j
< (int) sizeof(line_break
); j
++)
474 if (!((p
[i
] == '-') && (prefs
.word_mode
== WRAP
)))
475 if (p
[i
] == line_break
[j
])
476 return (unsigned char*) p
+i
;
482 static unsigned char* find_next_line(const unsigned char* cur_line
, bool *is_short
)
484 const unsigned char *next_line
= NULL
;
485 int size
, i
, j
, k
, width
, search_len
, spaces
, newlines
;
489 if (is_short
!= NULL
)
492 if BUFFER_OOB(cur_line
)
495 if (prefs
.view_mode
== WIDE
) {
496 search_len
= MAX_WIDTH
;
498 else { /* prefs.view_mode == NARROW */
499 search_len
= crop_at_width(cur_line
) - cur_line
;
502 size
= BUFFER_OOB(cur_line
+search_len
) ? buffer_end
-cur_line
: search_len
;
504 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
)) {
505 /* Need to scan ahead and possibly increase search_len and size,
506 or possibly set next_line at second hard return in a row. */
509 for (j
=k
=width
=spaces
=newlines
=0; ; j
++) {
510 if (BUFFER_OOB(cur_line
+j
))
513 size
= search_len
= j
;
520 if (prefs
.line_mode
== REFLOW
) {
523 next_line
= cur_line
+ size
;
524 return (unsigned char*) next_line
;
526 if (j
==0) /* i=1 is intentional */
527 for (i
=0; i
<par_indent_spaces
; i
++)
528 ADVANCE_COUNTERS(' ');
530 if (!first_chars
) spaces
++;
536 next_line
= cur_line
+ size
- spaces
;
537 if (next_line
!= cur_line
)
538 return (unsigned char*) next_line
;
544 if (BUFFER_OOB(cur_line
+size
) || size
> 2*search_len
)
547 spaces
= first_chars
? 0:1;
551 if (prefs
.line_mode
==JOIN
|| newlines
>0) {
554 ADVANCE_COUNTERS(' ');
556 size
= search_len
= j
;
562 /* REFLOW, multiple spaces between words: count only
563 * one. If more are needed, they will be added
567 ADVANCE_COUNTERS(' ');
569 size
= search_len
= j
;
580 /* find first hard return */
581 next_line
= find_first_feed(cur_line
, size
);
584 if (next_line
== NULL
)
585 if (size
== search_len
) {
586 if (prefs
.word_mode
== WRAP
) /* Find last space */
587 next_line
= find_last_space(cur_line
, size
);
589 if (next_line
== NULL
)
590 next_line
= crop_at_width(cur_line
);
592 if (prefs
.word_mode
== WRAP
)
594 i
<WRAP_TRIM
&& isspace(next_line
[0]) && !BUFFER_OOB(next_line
);
599 if (prefs
.line_mode
== EXPAND
)
600 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
601 if (next_line
[0] == 0)
602 if (next_line
!= cur_line
)
603 return (unsigned char*) next_line
;
605 /* If next_line is pointing to a zero, increment it; i.e.,
606 leave the terminator at the end of cur_line. If pointing
607 to a hyphen, increment only if there is room to display
608 the hyphen on current line (won't apply in WIDE mode,
609 since it's guarenteed there won't be room). */
610 if (!BUFFER_OOB(next_line
)) /* Not Null & not out of bounds */
611 if (next_line
[0] == 0)/* ||
612 (next_line[0] == '-' && next_line-cur_line < draw_columns)) */
615 if (BUFFER_OOB(next_line
))
621 return (unsigned char*) next_line
;
624 static unsigned char* find_prev_line(const unsigned char* cur_line
)
626 const unsigned char *prev_line
= NULL
;
627 const unsigned char *p
;
629 if BUFFER_OOB(cur_line
)
632 /* To wrap consistently at the same places, we must
633 start with a known hard return, then work downwards.
634 We can either search backwards for a hard return,
635 or simply start wrapping downwards from top of buffer.
636 If current line is not near top of buffer, this is
637 a file with long lines (paragraphs). We would need to
638 read earlier sectors before we could decide how to
639 properly wrap the lines above the current line, but
640 it probably is not worth the disk access. Instead,
641 start with top of buffer and wrap down from there.
642 This may result in some lines wrapping at different
643 points from where they wrap when scrolling down.
644 If buffer is at top of file, start at top of buffer. */
646 if ((prefs
.line_mode
== JOIN
) || (prefs
.line_mode
== REFLOW
))
647 prev_line
= p
= NULL
;
649 prev_line
= p
= find_last_feed(buffer
, cur_line
-buffer
-1);
650 /* Null means no line feeds in buffer above current line. */
652 if (prev_line
== NULL
)
653 if (BUFFER_BOF() || cur_line
- buffer
> READ_PREV_ZONE
)
654 prev_line
= p
= buffer
;
655 /* (else return NULL and read previous block) */
657 /* Wrap downwards until too far, then use the one before. */
658 while (p
< cur_line
&& p
!= NULL
) {
660 p
= find_next_line(prev_line
, NULL
);
663 if (BUFFER_OOB(prev_line
))
666 return (unsigned char*) prev_line
;
669 static void fill_buffer(long pos
, unsigned char* buf
, unsigned size
)
671 /* Read from file and preprocess the data */
672 /* To minimize disk access, always read on sector boundaries */
674 bool found_CR
= false;
676 rb
->lseek(fd
, pos
, SEEK_SET
);
677 numread
= rb
->read(fd
, buf
, size
);
678 rb
->button_clear_queue(); /* clear button queue */
680 for(i
= 0; i
< numread
; i
++) {
697 case 0: /* No break between case 0 and default, intentionally */
710 static int read_and_synch(int direction
)
712 /* Read next (or prev) block, and reposition global pointers. */
713 /* direction: 1 for down (i.e., further into file), -1 for up */
714 int move_size
, move_vector
, offset
;
715 unsigned char *fill_buf
;
717 if (direction
== -1) /* up */ {
718 move_size
= SMALL_BLOCK_SIZE
;
720 fill_buf
= TOP_SECTOR
;
721 rb
->memcpy(BOTTOM_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
722 rb
->memcpy(MID_SECTOR
, TOP_SECTOR
, SMALL_BLOCK_SIZE
);
725 if (prefs
.view_mode
== WIDE
) {
726 /* WIDE mode needs more buffer so we have to read smaller blocks */
727 move_size
= SMALL_BLOCK_SIZE
;
728 offset
= LARGE_BLOCK_SIZE
;
729 fill_buf
= BOTTOM_SECTOR
;
730 rb
->memcpy(TOP_SECTOR
, MID_SECTOR
, SMALL_BLOCK_SIZE
);
731 rb
->memcpy(MID_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
734 move_size
= LARGE_BLOCK_SIZE
;
735 offset
= SMALL_BLOCK_SIZE
;
736 fill_buf
= MID_SECTOR
;
737 rb
->memcpy(TOP_SECTOR
, BOTTOM_SECTOR
, SMALL_BLOCK_SIZE
);
740 move_vector
= direction
* move_size
;
741 screen_top_ptr
-= move_vector
;
742 file_pos
+= move_vector
;
743 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
744 fill_buffer(file_pos
+ offset
, fill_buf
, move_size
);
748 static void viewer_scroll_up(void)
752 p
= find_prev_line(screen_top_ptr
);
753 if (p
== NULL
&& !BUFFER_BOF()) {
755 p
= find_prev_line(screen_top_ptr
);
761 static void viewer_scroll_down(void)
763 if (next_screen_ptr
!= NULL
)
764 screen_top_ptr
= next_line_ptr
;
767 #ifdef HAVE_LCD_BITMAP
768 static void viewer_scrollbar(void) {
769 int items
, min_shown
, max_shown
;
771 items
= (int) file_size
; /* (SH1 int is same as long) */
772 min_shown
= (int) file_pos
+ (screen_top_ptr
- buffer
);
774 if (next_screen_ptr
== NULL
)
777 max_shown
= min_shown
+ (next_screen_ptr
- screen_top_ptr
);
779 rb
->gui_scrollbar_draw(rb
->screens
[SCREEN_MAIN
],0, 0, SCROLLBAR_WIDTH
-1,
780 LCD_HEIGHT
, items
, min_shown
, max_shown
, VERTICAL
);
784 static void viewer_draw(int col
)
786 int i
, j
, k
, line_len
, line_width
, resynch_move
, spaces
, left_col
=0;
787 int width
, extra_spaces
, indent_spaces
, spaces_per_word
;
788 bool multiple_spacing
, line_is_short
;
790 unsigned char *str
, *oldstr
;
791 unsigned char *line_begin
;
792 unsigned char *line_end
;
794 unsigned char scratch_buffer
[MAX_COLUMNS
+ 1];
795 unsigned char utf8_buffer
[MAX_COLUMNS
*4 + 1];
796 unsigned char *endptr
;
798 /* If col==-1 do all calculations but don't display */
800 #ifdef HAVE_LCD_BITMAP
801 left_col
= prefs
.need_scrollbar
? SCROLLBAR_WIDTH
:0;
805 rb
->lcd_clear_display();
808 line_begin
= line_end
= screen_top_ptr
;
810 for (i
= 0; i
< display_lines
; i
++) {
811 if (BUFFER_OOB(line_end
))
812 break; /* Happens after display last line at BUFFER_EOF() */
814 line_begin
= line_end
;
815 line_end
= find_next_line(line_begin
, &line_is_short
);
817 if (line_end
== NULL
) {
819 if (i
< display_lines
- 1 && !BUFFER_BOF()) {
821 rb
->lcd_clear_display();
823 for (; i
< display_lines
- 1; i
++)
826 line_begin
= line_end
= screen_top_ptr
;
831 line_end
= buffer_end
;
835 resynch_move
= read_and_synch(1); /* Read block & move ptrs */
836 line_begin
-= resynch_move
;
838 next_line_ptr
-= resynch_move
;
840 line_end
= find_next_line(line_begin
, NULL
);
841 if (line_end
== NULL
) /* Should not really happen */
845 line_len
= line_end
- line_begin
;
847 /* calculate line_len */
848 str
= oldstr
= line_begin
;
850 while (str
< line_end
) {
852 str
= crop_at_width(str
);
855 line_width
= j
*draw_columns
;
856 while (oldstr
< line_end
) {
857 oldstr
= get_ucs(oldstr
, &ch
);
858 line_width
+= glyph_width(ch
);
861 if (prefs
.line_mode
== JOIN
) {
862 if (line_begin
[0] == 0) {
864 if (prefs
.word_mode
== CHOP
)
869 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
870 if (k
== MAX_COLUMNS
)
880 scratch_buffer
[k
++] = ' ';
885 scratch_buffer
[k
++] = ' ';
886 if (k
== MAX_COLUMNS
- 1)
889 scratch_buffer
[k
++] = c
;
894 scratch_buffer
[k
] = 0;
895 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
896 prefs
.encoding
, draw_columns
/glyph_width('i'));
900 else if (prefs
.line_mode
== REFLOW
) {
901 if (line_begin
[0] == 0) {
903 if (prefs
.word_mode
== CHOP
)
910 if (!line_is_short
) {
911 multiple_spacing
= false;
913 for (str
= line_begin
; str
< line_end
; ) {
914 str
= get_ucs(str
, &ch
);
918 if ((str
== line_begin
) && (prefs
.word_mode
==WRAP
))
919 /* special case: indent the paragraph,
920 * don't count spaces */
921 indent_spaces
= par_indent_spaces
;
922 else if (!multiple_spacing
)
924 multiple_spacing
= true;
927 multiple_spacing
= false;
928 width
+= glyph_width(ch
);
932 if (multiple_spacing
) spaces
--;
935 /* total number of spaces to insert between words */
936 extra_spaces
= (draw_columns
-width
)/glyph_width(' ')
938 /* number of spaces between each word*/
939 spaces_per_word
= extra_spaces
/ spaces
;
940 /* number of words with n+1 spaces (to fill up) */
941 extra_spaces
= extra_spaces
% spaces
;
942 if (spaces_per_word
> 2) { /* too much spacing is awful */
946 } else { /* this doesn't matter much... no spaces anyway */
947 spaces_per_word
= extra_spaces
= 0;
949 } else { /* end of a paragraph: don't fill line */
954 multiple_spacing
= false;
955 for (j
=k
=spaces
=0; j
< line_len
; j
++) {
956 if (k
== MAX_COLUMNS
)
963 if (j
==0 && prefs
.word_mode
==WRAP
) { /* indent paragraph */
964 for (j
=0; j
<par_indent_spaces
; j
++)
965 scratch_buffer
[k
++] = ' ';
968 else if (!multiple_spacing
) {
969 for (width
= spaces
<extra_spaces
? -1:0; width
< spaces_per_word
; width
++)
970 scratch_buffer
[k
++] = ' ';
973 multiple_spacing
= true;
976 scratch_buffer
[k
++] = c
;
977 multiple_spacing
= false;
983 scratch_buffer
[k
] = 0;
984 endptr
= rb
->iso_decode(scratch_buffer
+ col
, utf8_buffer
,
985 prefs
.encoding
, k
-col
);
989 else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */
991 if (line_width
> col
) {
992 str
= oldstr
= line_begin
;
995 while( (width
<draw_columns
) && (oldstr
<line_end
) )
997 oldstr
= get_ucs(oldstr
, &ch
);
999 k
-= glyph_width(ch
);
1000 line_begin
= oldstr
;
1002 width
+= glyph_width(ch
);
1006 if(prefs
.view_mode
==WIDE
)
1007 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1008 prefs
.encoding
, oldstr
-line_begin
);
1010 endptr
= rb
->iso_decode(line_begin
, utf8_buffer
,
1011 prefs
.encoding
, line_end
-line_begin
);
1015 if (col
!= -1 && line_width
> col
)
1016 #ifdef HAVE_LCD_BITMAP
1017 rb
->lcd_putsxy(left_col
, i
*pf
->height
, utf8_buffer
);
1019 rb
->lcd_puts(left_col
, i
, utf8_buffer
);
1021 if (line_width
> max_line_len
)
1022 max_line_len
= line_width
;
1025 next_line_ptr
= line_end
;
1027 next_screen_ptr
= line_end
;
1028 if (BUFFER_OOB(next_screen_ptr
))
1029 next_screen_ptr
= NULL
;
1031 #ifdef HAVE_LCD_BITMAP
1032 next_screen_to_draw_ptr
= prefs
.page_mode
==OVERLAP
? line_begin
: next_screen_ptr
;
1034 if (prefs
.need_scrollbar
)
1037 next_screen_to_draw_ptr
= next_screen_ptr
;
1044 static void viewer_top(void)
1046 /* Read top of file into buffer
1047 and point screen pointer to top */
1051 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1052 fill_buffer(0, buffer
, buffer_size
);
1055 screen_top_ptr
= buffer
;
1058 static void viewer_bottom(void)
1060 /* Read bottom of file into buffer
1061 and point screen pointer to bottom */
1064 if (file_size
> buffer_size
) {
1065 /* Find last buffer in file, round up to next sector boundary */
1066 last_sectors
= file_size
- buffer_size
+ SMALL_BLOCK_SIZE
;
1067 last_sectors
/= SMALL_BLOCK_SIZE
;
1068 last_sectors
*= SMALL_BLOCK_SIZE
;
1074 if (file_pos
!= last_sectors
)
1076 file_pos
= last_sectors
;
1077 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1078 fill_buffer(last_sectors
, buffer
, buffer_size
);
1081 screen_top_ptr
= buffer_end
-1;
1084 #ifdef HAVE_LCD_BITMAP
1085 static void init_need_scrollbar(void) {
1086 /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
1087 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
1089 prefs
.need_scrollbar
= NEED_SCROLLBAR();
1090 draw_columns
= prefs
.need_scrollbar
? display_columns
-SCROLLBAR_WIDTH
: display_columns
;
1091 par_indent_spaces
= draw_columns
/(5*glyph_width(' '));
1094 #define init_need_scrollbar()
1097 static bool viewer_init(void)
1099 #ifdef HAVE_LCD_BITMAP
1101 pf
= rb
->font_get(FONT_UI
);
1103 display_lines
= LCD_HEIGHT
/ pf
->height
;
1104 draw_columns
= display_columns
= LCD_WIDTH
;
1106 /* REAL fixed pitch :) all chars use up 1 cell */
1108 draw_columns
= display_columns
= 11;
1109 par_indent_spaces
= 2;
1112 fd
= rb
->open(file_name
, O_RDONLY
);
1116 file_size
= rb
->filesize(fd
);
1120 /* Init mac_text value used in processing buffer */
1126 static void viewer_default_settings(void)
1128 prefs
.word_mode
= WRAP
;
1129 prefs
.line_mode
= NORMAL
;
1130 prefs
.view_mode
= NARROW
;
1131 prefs
.scroll_mode
= PAGE
;
1132 #ifdef HAVE_LCD_BITMAP
1133 prefs
.page_mode
= NO_OVERLAP
;
1134 prefs
.scrollbar_mode
= SB_OFF
;
1136 prefs
.autoscroll_speed
= 1;
1137 /* Set codepage to system default */
1138 prefs
.encoding
= rb
->global_settings
->default_codepage
;
1141 static void viewer_load_settings(void) /* same name as global, but not the same file.. */
1144 struct bookmark_file_data
*data
;
1145 struct bookmarked_file_info this_bookmark
;
1147 /* read settings file */
1148 settings_fd
=rb
->open(SETTINGS_FILE
, O_RDONLY
);
1149 if ((settings_fd
>= 0) && (rb
->filesize(settings_fd
) == sizeof(struct preferences
)))
1151 rb
->read(settings_fd
, &prefs
, sizeof(struct preferences
));
1152 rb
->close(settings_fd
);
1156 /* load default settings if there is no settings file */
1157 viewer_default_settings();
1160 rb
->memcpy(&old_prefs
, &prefs
, sizeof(struct preferences
));
1162 data
= (struct bookmark_file_data
*)buffer
; /* grab the text buffer */
1163 data
->bookmarked_files_count
= 0;
1165 /* read bookmarks if file exists */
1166 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_RDONLY
);
1167 if (settings_fd
>= 0)
1169 /* figure out how many items to read */
1170 rb
->read(settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1171 if (data
->bookmarked_files_count
> MAX_BOOKMARKED_FILES
)
1172 data
->bookmarked_files_count
= MAX_BOOKMARKED_FILES
;
1173 rb
->read(settings_fd
, data
->bookmarks
,
1174 sizeof(struct bookmarked_file_info
) * data
->bookmarked_files_count
);
1175 rb
->close(settings_fd
);
1179 screen_top_ptr
= buffer
;
1181 /* check if current file is in list */
1182 for (i
=0; i
< data
->bookmarked_files_count
; i
++)
1184 if (!rb
->strcmp(file_name
, data
->bookmarks
[i
].filename
))
1186 int screen_pos
= data
->bookmarks
[i
].file_position
+ data
->bookmarks
[i
].top_ptr_pos
;
1187 int screen_top
= screen_pos
% buffer_size
;
1188 file_pos
= screen_pos
- screen_top
;
1189 screen_top_ptr
= buffer
+ screen_top
;
1194 this_bookmark
.file_position
= file_pos
;
1195 this_bookmark
.top_ptr_pos
= screen_top_ptr
- buffer
;
1197 rb
->memset(&this_bookmark
.filename
[0],0,MAX_PATH
);
1198 rb
->strcpy(this_bookmark
.filename
,file_name
);
1200 /* prevent potential slot overflow */
1201 if (i
>= data
->bookmarked_files_count
)
1203 if (i
< MAX_BOOKMARKED_FILES
)
1204 data
->bookmarked_files_count
++;
1206 i
= MAX_BOOKMARKED_FILES
-1;
1209 /* write bookmark file with spare slot in first position
1210 to be filled in by viewer_save_settings */
1211 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1212 if (settings_fd
>=0 )
1215 rb
->write (settings_fd
, &data
->bookmarked_files_count
, sizeof(signed int));
1217 /* write the current bookmark */
1218 rb
->write (settings_fd
, &this_bookmark
, sizeof(struct bookmarked_file_info
));
1220 /* write everything that was before this bookmark */
1221 rb
->write (settings_fd
, data
->bookmarks
, sizeof(struct bookmarked_file_info
)*i
);
1223 rb
->close(settings_fd
);
1226 buffer_end
= BUFFER_END(); /* Update whenever file_pos changes */
1228 if (BUFFER_OOB(screen_top_ptr
))
1230 screen_top_ptr
= buffer
;
1233 fill_buffer(file_pos
, buffer
, buffer_size
);
1235 /* remember the current position */
1236 start_position
= file_pos
+ screen_top_ptr
- buffer
;
1238 init_need_scrollbar();
1241 static void viewer_save_settings(void)/* same name as global, but not the same file.. */
1245 /* save the viewer settings if they have been changed */
1246 if (rb
->memcmp(&prefs
, &old_prefs
, sizeof(struct preferences
)))
1248 settings_fd
= rb
->creat(SETTINGS_FILE
); /* create the settings file */
1250 if (settings_fd
>= 0 )
1252 rb
->write (settings_fd
, &prefs
, sizeof(struct preferences
));
1253 rb
->close(settings_fd
);
1257 /* save the bookmark if the position has changed */
1258 if (file_pos
+ screen_top_ptr
- buffer
!= start_position
)
1260 settings_fd
= rb
->open(BOOKMARKS_FILE
, O_WRONLY
|O_CREAT
);
1262 if (settings_fd
>= 0 )
1264 struct bookmarked_file_info b
;
1265 b
.file_position
= file_pos
+ screen_top_ptr
- buffer
;
1266 b
.top_ptr_pos
= 0; /* this is only kept for legassy reasons */
1267 rb
->memset(&b
.filename
[0],0,MAX_PATH
);
1268 rb
->strcpy(b
.filename
,file_name
);
1269 rb
->PREFIX(lseek
)(settings_fd
,sizeof(signed int),SEEK_SET
);
1270 rb
->write (settings_fd
, &b
, sizeof(struct bookmarked_file_info
));
1271 rb
->close(settings_fd
);
1276 static void viewer_exit(void *parameter
)
1280 viewer_save_settings();
1284 static int col_limit(int col
)
1289 if (col
> max_line_len
- 2*glyph_width('o'))
1290 col
= max_line_len
- 2*glyph_width('o');
1295 /* settings helper functions */
1297 static bool encoding_setting(void)
1299 static const struct opt_items names
[] = {
1304 {"ISO-8859-11", -1},
1316 return rb
->set_option("Encoding", &prefs
.encoding
, INT
, names
,
1317 sizeof(names
) / sizeof(names
[0]), NULL
);
1320 static bool word_wrap_setting(void)
1322 static const struct opt_items names
[] = {
1324 {"Off (Chop Words)", -1},
1327 return rb
->set_option("Word Wrap", &prefs
.word_mode
, INT
,
1331 static bool line_mode_setting(void)
1333 static const struct opt_items names
[] = {
1336 {"Expand Lines", -1},
1337 #ifdef HAVE_LCD_BITMAP
1338 {"Reflow Lines", -1},
1342 return rb
->set_option("Line Mode", &prefs
.line_mode
, INT
, names
,
1343 sizeof(names
) / sizeof(names
[0]), NULL
);
1346 static bool view_mode_setting(void)
1348 static const struct opt_items names
[] = {
1349 {"No (Narrow)", -1},
1353 ret
= rb
->set_option("Wide View", &prefs
.view_mode
, INT
,
1355 if (prefs
.view_mode
== NARROW
)
1360 static bool scroll_mode_setting(void)
1362 static const struct opt_items names
[] = {
1363 {"Scroll by Page", -1},
1364 {"Scroll by Line", -1},
1367 return rb
->set_option("Scroll Mode", &prefs
.scroll_mode
, INT
,
1371 #ifdef HAVE_LCD_BITMAP
1372 static bool page_mode_setting(void)
1374 static const struct opt_items names
[] = {
1379 return rb
->set_option("Overlap Pages", &prefs
.page_mode
, INT
,
1383 static bool scrollbar_setting(void)
1385 static const struct opt_items names
[] = {
1390 return rb
->set_option("Show Scrollbar", &prefs
.scrollbar_mode
, INT
,
1395 static bool autoscroll_speed_setting(void)
1397 return rb
->set_int("Auto-scroll Speed", "", UNIT_INT
,
1398 &prefs
.autoscroll_speed
, NULL
, 1, 1, 10, NULL
);
1401 static bool viewer_options_menu(void)
1406 static const struct menu_item items
[] = {
1407 {"Encoding", encoding_setting
},
1408 {"Word Wrap", word_wrap_setting
},
1409 {"Line Mode", line_mode_setting
},
1410 {"Wide View", view_mode_setting
},
1411 #ifdef HAVE_LCD_BITMAP
1412 {"Show Scrollbar", scrollbar_setting
},
1413 {"Overlap Pages", page_mode_setting
},
1415 {"Scroll Mode", scroll_mode_setting
},
1416 {"Auto-Scroll Speed", autoscroll_speed_setting
},
1418 m
= menu_init(rb
, items
, sizeof(items
) / sizeof(*items
),
1419 NULL
, NULL
, NULL
, NULL
);
1421 result
= menu_run(m
);
1423 #ifdef HAVE_LCD_BITMAP
1424 rb
->lcd_setmargins(0,0);
1426 /* Show-scrollbar mode for current view-width mode */
1427 init_need_scrollbar();
1432 static void viewer_menu(void)
1436 static const struct menu_item items
[] = {
1438 {"Viewer Options", NULL
},
1439 {"Show Playback Menu", NULL
},
1443 m
= menu_init(rb
, items
, sizeof(items
) / sizeof(*items
), NULL
, NULL
, NULL
, NULL
);
1444 result
=menu_show(m
);
1452 case 1: /* change settings */
1453 done
= viewer_options_menu();
1455 case 2: /* playback control */
1456 playback_control(rb
, NULL
);
1458 case 3: /* return */
1462 #ifdef HAVE_LCD_BITMAP
1463 rb
->lcd_setmargins(0,0);
1468 enum plugin_status
plugin_start(const struct plugin_api
* api
, const void* file
)
1471 int lastbutton
= BUTTON_NONE
;
1472 bool autoscroll
= false;
1476 old_tick
= *rb
->current_tick
;
1478 /* get the plugin buffer */
1479 buffer
= rb
->plugin_get_buffer((size_t *)&buffer_size
);
1482 return PLUGIN_ERROR
;
1487 rb
->splash(HZ
, "Error opening file.");
1488 return PLUGIN_ERROR
;
1491 viewer_load_settings(); /* load the preferences and bookmark */
1494 rb
->lcd_set_backdrop(NULL
);
1503 if(old_tick
<= *rb
->current_tick
- (110-prefs
.autoscroll_speed
*10))
1505 viewer_scroll_down();
1507 old_tick
= *rb
->current_tick
;
1511 button
= rb
->button_get_w_tmo(HZ
/10);
1517 case VIEWER_AUTOSCROLL
:
1518 #ifdef VIEWER_AUTOSCROLL_PRE
1519 if (lastbutton
!= VIEWER_AUTOSCROLL_PRE
)
1522 autoscroll
= !autoscroll
;
1525 case VIEWER_PAGE_UP
:
1526 case VIEWER_PAGE_UP
| BUTTON_REPEAT
:
1527 if (prefs
.scroll_mode
== PAGE
)
1530 #ifdef HAVE_LCD_BITMAP
1531 for (i
= prefs
.page_mode
==OVERLAP
? 1:0; i
< display_lines
; i
++)
1533 for (i
= 0; i
< display_lines
; i
++)
1539 old_tick
= *rb
->current_tick
;
1543 case VIEWER_PAGE_DOWN
:
1544 case VIEWER_PAGE_DOWN
| BUTTON_REPEAT
:
1545 if (prefs
.scroll_mode
== PAGE
)
1548 if (next_screen_ptr
!= NULL
)
1549 screen_top_ptr
= next_screen_to_draw_ptr
;
1552 viewer_scroll_down();
1553 old_tick
= *rb
->current_tick
;
1557 case VIEWER_SCREEN_LEFT
:
1558 case VIEWER_SCREEN_LEFT
| BUTTON_REPEAT
:
1559 if (prefs
.view_mode
== WIDE
) {
1561 col
-= draw_columns
;
1562 col
= col_limit(col
);
1564 else { /* prefs.view_mode == NARROW */
1572 case VIEWER_SCREEN_RIGHT
:
1573 case VIEWER_SCREEN_RIGHT
| BUTTON_REPEAT
:
1574 if (prefs
.view_mode
== WIDE
) {
1576 col
+= draw_columns
;
1577 col
= col_limit(col
);
1579 else { /* prefs.view_mode == NARROW */
1580 /* Bottom of file */
1587 #ifdef VIEWER_LINE_UP
1588 case VIEWER_LINE_UP
:
1589 case VIEWER_LINE_UP
| BUTTON_REPEAT
:
1590 /* Scroll up one line */
1592 old_tick
= *rb
->current_tick
;
1596 case VIEWER_LINE_DOWN
:
1597 case VIEWER_LINE_DOWN
| BUTTON_REPEAT
:
1598 /* Scroll down one line */
1599 if (next_screen_ptr
!= NULL
)
1600 screen_top_ptr
= next_line_ptr
;
1601 old_tick
= *rb
->current_tick
;
1605 #ifdef VIEWER_COLUMN_LEFT
1606 case VIEWER_COLUMN_LEFT
:
1607 case VIEWER_COLUMN_LEFT
| BUTTON_REPEAT
:
1608 if (prefs
.view_mode
== WIDE
) {
1609 /* Scroll left one column */
1610 col
-= glyph_width('o');
1611 col
= col_limit(col
);
1616 case VIEWER_COLUMN_RIGHT
:
1617 case VIEWER_COLUMN_RIGHT
| BUTTON_REPEAT
:
1618 if (prefs
.view_mode
== WIDE
) {
1619 /* Scroll right one column */
1620 col
+= glyph_width('o');
1621 col
= col_limit(col
);
1627 #ifdef VIEWER_RC_QUIT
1628 case VIEWER_RC_QUIT
:
1636 if (rb
->default_event_handler_ex(button
, viewer_exit
, NULL
)
1637 == SYS_USB_CONNECTED
)
1638 return PLUGIN_USB_CONNECTED
;
1641 if (button
!= BUTTON_NONE
)
1643 lastbutton
= button
;