summaryrefslogtreecommitdiff
path: root/apps/plugins/viewer.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/viewer.c')
-rw-r--r--apps/plugins/viewer.c415
1 files changed, 415 insertions, 0 deletions
diff --git a/apps/plugins/viewer.c b/apps/plugins/viewer.c
new file mode 100644
index 0000000000..f8dc309a6e
--- /dev/null
+++ b/apps/plugins/viewer.c
@@ -0,0 +1,415 @@
1/***************************************************************************
2 *
3 * __________ __ ___.
4 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8 * \/ \/ \/ \/ \/
9 * $Id$
10 *
11 * Copyright (C) 2002 Gilles Roux
12 *
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.
15 *
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
18 *
19 ****************************************************************************/
20#include "plugin.h"
21
22#define BUFFER_SIZE 1024
23#define OUTSIDE_BUFFER -10
24#define OUTSIDE_FILE -11
25
26static int fd;
27static int file_size;
28
29static char buffer[BUFFER_SIZE+1];
30static int buffer_pos; /* Position of the buffer in the file */
31
32static char display_lines; /* number of lines on the display */
33static char display_columns; /* number of columns on the display */
34static int begin_line; /* Index of the first line displayed on the lcd */
35static int end_line; /* Index of the last line displayed on the lcd */
36static int begin_line_pos; /* Position of the first_line in the bufffer */
37static int end_line_pos; /* Position of the last_line in the buffer */
38static struct plugin_api* rb;
39
40/*
41 * Known issue: The caching algorithm will fail (display incoherent data) if
42 * the total space of the lines that are displayed on the screen exceeds the
43 * buffer size (only happens with very long lines).
44 */
45
46static void display_line_count(void)
47{
48#ifdef HAVE_LCD_BITMAP
49 int w,h;
50 rb->lcd_getstringsize("M", &w, &h);
51 display_lines = LCD_HEIGHT / h;
52 display_columns = LCD_WIDTH / w;
53#else
54 display_lines = 2;
55 display_columns = 11;
56#endif
57}
58
59static int find_next_line(int pos)
60{
61 int i;
62
63 if (pos==OUTSIDE_BUFFER || pos==OUTSIDE_FILE)
64 return pos;
65
66 i = pos;
67 if (buffer_pos+i>=file_size) {
68 return OUTSIDE_FILE;
69 }
70 while (1) {
71 i++;
72 if (buffer_pos+i==file_size) {
73 return i;
74 }
75 if (i>=BUFFER_SIZE) {
76 return OUTSIDE_BUFFER;
77 }
78 if (buffer[i]==0) {
79 return i;
80 }
81 }
82}
83
84static int find_prev_line(int pos)
85{
86 int i;
87
88 if (pos==OUTSIDE_BUFFER || pos==OUTSIDE_FILE)
89 return pos;
90
91 i = pos;
92 if (buffer_pos+i<0) {
93 return OUTSIDE_FILE;
94 }
95 while (1) {
96 i--;
97 if (buffer_pos+i<0) {
98 return i;
99 }
100 if (i<0) {
101 return OUTSIDE_BUFFER;
102 }
103 if (buffer[i]==0) {
104 return i;
105 }
106 }
107}
108
109static void viewer_draw(int col)
110{
111 int i, j;
112 char* str;
113 int line_pos;
114
115 rb->lcd_clear_display();
116
117 line_pos = begin_line_pos;
118
119 for (i=0; i <= end_line - begin_line; i++) {
120 if (line_pos == OUTSIDE_BUFFER ||
121 line_pos == OUTSIDE_FILE)
122 break;
123 str = buffer + line_pos + 1;
124 for (j=0; j<col && *str!=0; ++j)
125 str++;
126 rb->lcd_puts(0, i, str);
127 line_pos = find_next_line(line_pos);
128 }
129#ifdef HAVE_LCD_BITMAP
130 rb->lcd_update();
131#endif
132}
133
134static void fill_buffer(int pos)
135{
136 int i;
137 int numread;
138
139 if (pos>=file_size-BUFFER_SIZE)
140 pos = file_size-BUFFER_SIZE;
141 if (pos<0)
142 pos = 0;
143
144 rb->lseek(fd, pos, SEEK_SET);
145 numread = rb->read(fd, buffer, BUFFER_SIZE);
146
147 begin_line_pos -= pos - buffer_pos;
148 end_line_pos -= pos - buffer_pos;
149 buffer_pos = pos;
150
151 buffer[numread] = 0;
152 for(i=0;i<numread;i++) {
153 switch(buffer[i]) {
154 case '\r':
155 buffer[i] = ' ';
156 break;
157 case '\n':
158 buffer[i] = 0;
159 break;
160 default:
161 break;
162 }
163 }
164}
165
166static bool viewer_init(char* file)
167{
168 int i;
169 int ret;
170
171 fd = rb->open(file, O_RDONLY);
172 if (fd==-1)
173 return false;
174
175 file_size = rb->lseek(fd, 0, SEEK_END);
176
177 buffer_pos = 0;
178 begin_line = 0;
179 begin_line_pos = -1;
180 end_line = -1;
181 end_line_pos = -1;
182 fill_buffer(0);
183 display_line_count();
184 for (i=0; i<display_lines; ++i) {
185 ret = find_next_line(end_line_pos);
186 if (ret!=OUTSIDE_FILE && ret!=OUTSIDE_BUFFER) {
187 end_line_pos = ret;
188 end_line++;
189 }
190 }
191
192 return true;
193}
194
195static void viewer_exit(void)
196{
197 rb->close(fd);
198}
199
200static void viewer_scroll_down(void)
201{
202 int ret;
203
204 ret = find_next_line(end_line_pos);
205 switch ( ret ) {
206 case OUTSIDE_BUFFER:
207 begin_line_pos = find_next_line(begin_line_pos);
208 fill_buffer(begin_line_pos+buffer_pos);
209 end_line_pos = find_next_line(end_line_pos);
210 break;
211
212 case OUTSIDE_FILE:
213 return;
214
215 default:
216 begin_line_pos = find_next_line(begin_line_pos);
217 end_line_pos = ret;
218 break;
219 }
220 begin_line++;
221 end_line++;
222}
223
224static void viewer_scroll_up(void)
225{
226 int ret;
227
228 ret = find_prev_line(begin_line_pos);
229 switch ( ret ) {
230 case OUTSIDE_BUFFER:
231 end_line_pos = find_prev_line(end_line_pos);
232 fill_buffer(buffer_pos+end_line_pos-BUFFER_SIZE);
233 begin_line_pos = find_prev_line(begin_line_pos);
234 break;
235
236 case OUTSIDE_FILE:
237 return;
238
239 default:
240 end_line_pos = find_prev_line(end_line_pos);
241 begin_line_pos = ret;
242 break;
243 }
244 begin_line--;
245 end_line--;
246}
247
248static int pagescroll(int col)
249{
250 bool exit = false;
251 int i;
252
253 while (!exit) {
254 switch (rb->button_get(true)) {
255#ifdef HAVE_RECORDER_KEYPAD
256 case BUTTON_ON | BUTTON_UP:
257 case BUTTON_ON | BUTTON_UP | BUTTON_REPEAT:
258#else
259 case BUTTON_ON | BUTTON_LEFT:
260 case BUTTON_ON | BUTTON_LEFT | BUTTON_REPEAT:
261#endif
262 for (i=0; i<display_lines; i++)
263 viewer_scroll_up();
264 break;
265
266#ifdef HAVE_RECORDER_KEYPAD
267 case BUTTON_ON | BUTTON_DOWN:
268 case BUTTON_ON | BUTTON_DOWN | BUTTON_REPEAT:
269#else
270 case BUTTON_ON | BUTTON_RIGHT:
271 case BUTTON_ON | BUTTON_RIGHT | BUTTON_REPEAT:
272#endif
273 for (i=0; i<display_lines; i++)
274 viewer_scroll_down();
275 break;
276
277#ifdef HAVE_RECORDER_KEYPAD
278 case BUTTON_ON | BUTTON_LEFT:
279 case BUTTON_ON | BUTTON_LEFT | BUTTON_REPEAT:
280#else
281 case BUTTON_ON | BUTTON_MENU | BUTTON_LEFT:
282 case BUTTON_ON | BUTTON_MENU | BUTTON_LEFT | BUTTON_REPEAT:
283#endif
284 col -= display_columns;
285 if (col < 0)
286 col = 0;
287 break;
288
289#ifdef HAVE_RECORDER_KEYPAD
290 case BUTTON_ON | BUTTON_RIGHT:
291 case BUTTON_ON | BUTTON_RIGHT | BUTTON_REPEAT:
292#else
293 case BUTTON_ON | BUTTON_MENU | BUTTON_RIGHT:
294 case BUTTON_ON | BUTTON_MENU | BUTTON_RIGHT | BUTTON_REPEAT:
295#endif
296 col += display_columns;
297 break;
298
299 case BUTTON_ON | BUTTON_REL:
300#ifdef HAVE_RECORDER_KEYPAD
301 case BUTTON_ON | BUTTON_DOWN | BUTTON_REL:
302 case BUTTON_ON | BUTTON_UP | BUTTON_REL:
303#else
304 case BUTTON_ON | BUTTON_RIGHT | BUTTON_REL:
305 case BUTTON_ON | BUTTON_LEFT | BUTTON_REL:
306 case BUTTON_ON | BUTTON_MENU | BUTTON_RIGHT | BUTTON_REL:
307 case BUTTON_ON | BUTTON_MENU | BUTTON_LEFT | BUTTON_REL:
308#endif
309 exit = true;
310 break;
311 }
312 if ( !exit )
313 viewer_draw(col);
314 }
315
316 return col;
317}
318
319enum plugin_status plugin_start(struct plugin_api* api, void* file)
320{
321 bool exit=false;
322 int button;
323 int col = 0;
324 int ok;
325
326 TEST_PLUGIN_API(api);
327 rb = api;
328
329 if (!file)
330 return PLUGIN_ERROR;
331
332 ok = viewer_init(file);
333 if (!ok) {
334 rb->splash(HZ, 0, false, "Error");
335 viewer_exit();
336 return PLUGIN_OK;
337 }
338
339 viewer_draw(col);
340 while (!exit) {
341 button = rb->button_get(true);
342
343 switch ( button ) {
344
345#ifdef HAVE_RECORDER_KEYPAD
346 case BUTTON_F1:
347 case BUTTON_OFF:
348#else
349 case BUTTON_STOP:
350#endif
351 viewer_exit();
352 exit = true;
353 break;
354
355#ifdef HAVE_RECORDER_KEYPAD
356 case BUTTON_UP:
357 case BUTTON_UP | BUTTON_REPEAT:
358#else
359 case BUTTON_LEFT:
360 case BUTTON_LEFT | BUTTON_REPEAT:
361#endif
362 viewer_scroll_up();
363 viewer_draw(col);
364 break;
365
366#ifdef HAVE_RECORDER_KEYPAD
367 case BUTTON_DOWN:
368 case BUTTON_DOWN | BUTTON_REPEAT:
369#else
370 case BUTTON_RIGHT:
371 case BUTTON_RIGHT | BUTTON_REPEAT:
372#endif
373 viewer_scroll_down();
374 viewer_draw(col);
375 break;
376
377#ifdef HAVE_RECORDER_KEYPAD
378 case BUTTON_LEFT:
379 case BUTTON_LEFT | BUTTON_REPEAT:
380#else
381 case BUTTON_MENU | BUTTON_LEFT:
382 case BUTTON_MENU | BUTTON_LEFT | BUTTON_REPEAT:
383#endif
384 col--;
385 if (col < 0)
386 col = 0;
387 viewer_draw(col);
388 break;
389
390#ifdef HAVE_RECORDER_KEYPAD
391 case BUTTON_RIGHT:
392 case BUTTON_RIGHT | BUTTON_REPEAT:
393#else
394 case BUTTON_MENU | BUTTON_RIGHT:
395 case BUTTON_MENU | BUTTON_RIGHT | BUTTON_REPEAT:
396#endif
397 col++;
398 viewer_draw(col);
399 break;
400
401 case BUTTON_ON:
402#ifdef HAVE_PLAYER_KEYPAD
403 case BUTTON_ON | BUTTON_MENU:
404#endif
405 col = pagescroll(col);
406 break;
407
408 case SYS_USB_CONNECTED:
409 rb->usb_screen();
410 viewer_exit();
411 return PLUGIN_USB_CONNECTED;
412 }
413 }
414 return PLUGIN_OK;
415}