Initial 800x480 cabbiev2 port, based on 480x800x16 one
[kugel-rb.git] / apps / plugins / imageviewer / imageviewer.c
blob01b9f31be10781d2350a6224a3d3695190fb50b3
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * user intereface of image viewer
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 * TODO:
24 * - check magick value in file header to determine image type.
26 #include "plugin.h"
27 #include <lib/playback_control.h>
28 #include <lib/helper.h>
29 #include <lib/configfile.h>
30 #include "imageviewer.h"
31 #include "image_decoder.h"
35 #ifdef USEGSLIB
36 GREY_INFO_STRUCT
37 #endif
39 /* Headings */
40 #define DIR_PREV 1
41 #define DIR_NEXT -1
42 #define DIR_NONE 0
44 /******************************* Globals ***********************************/
46 /* Persistent configuration */
47 #define IMGVIEW_CONFIGFILE "imageviewer.cfg"
48 #define IMGVIEW_SETTINGS_MINVERSION 1
49 #define IMGVIEW_SETTINGS_VERSION 2
51 /* Slideshow times */
52 #define SS_MIN_TIMEOUT 1
53 #define SS_MAX_TIMEOUT 20
54 #define SS_DEFAULT_TIMEOUT 5
56 #ifdef HAVE_LCD_COLOR
57 /* needed for value of settings */
58 #include "jpeg/yuv2rgb.h"
59 #endif
61 static struct imgview_settings settings =
63 #ifdef HAVE_LCD_COLOR
64 COLOURMODE_COLOUR,
65 DITHER_NONE,
66 #endif
67 SS_DEFAULT_TIMEOUT
69 static struct imgview_settings old_settings;
71 static struct configdata config[] =
73 #ifdef HAVE_LCD_COLOR
74 { TYPE_ENUM, 0, COLOUR_NUM_MODES, { .int_p = &settings.jpeg_colour_mode },
75 "Colour Mode", (char *[]){ "Colour", "Grayscale" } },
76 { TYPE_ENUM, 0, DITHER_NUM_MODES, { .int_p = &settings.jpeg_dither_mode },
77 "Dither Mode", (char *[]){ "None", "Ordered", "Diffusion" } },
78 #endif
79 { TYPE_INT, SS_MIN_TIMEOUT, SS_MAX_TIMEOUT,
80 { .int_p = &settings.ss_timeout }, "Slideshow Time", NULL },
83 static void cb_progress(int current, int total);
85 static struct imgdec_api iv_api = {
86 .settings = &settings,
87 .slideshow_enabled = false,
88 .running_slideshow = false,
89 #ifdef DISK_SPINDOWN
90 .immediate_ata_off = false,
91 #endif
92 #ifdef USE_PLUG_BUF
93 .plug_buf = true,
94 #endif
96 .cb_progress = cb_progress,
98 #ifdef USEGSLIB
99 .gray_bitmap_part = myxlcd_ub_(gray_bitmap_part),
100 #endif
103 /**************** begin Application ********************/
106 /************************* Globals ***************************/
108 #ifdef HAVE_LCD_COLOR
109 static fb_data rgb_linebuf[LCD_WIDTH]; /* Line buffer for scrolling when
110 DITHER_DIFFUSION is set */
111 #endif
113 /* buffer to load image decoder */
114 static unsigned char* decoder_buf;
115 static size_t decoder_buf_size;
116 /* the remaining free part of the buffer for loaded+resized images */
117 static unsigned char* buf;
118 static size_t buf_size;
120 static int ds, ds_min, ds_max; /* downscaling and limits */
121 static struct image_info image_info;
123 /* the current full file name */
124 static char np_file[MAX_PATH];
125 static int curfile = -1, direction = DIR_NEXT, entries = 0;
127 /* list of the supported image files */
128 static char **file_pt;
130 static const struct image_decoder *imgdec = NULL;
131 static enum image_type image_type = IMAGE_UNKNOWN;
133 /************************* Implementation ***************************/
135 /* Read directory contents for scrolling. */
136 static void get_pic_list(void)
138 struct tree_context *tree = rb->tree_get_context();
139 struct entry *dircache = tree->dircache;
140 int i;
141 char *pname;
143 file_pt = (char **) buf;
145 /* Remove path and leave only the name.*/
146 pname = rb->strrchr(np_file,'/');
147 pname++;
149 for (i = 0; i < tree->filesindir && buf_size > sizeof(char**); i++)
151 if (!(dircache[i].attr & ATTR_DIRECTORY)
152 && get_image_type(dircache[i].name) != IMAGE_UNKNOWN)
154 file_pt[entries] = dircache[i].name;
155 /* Set Selected File. */
156 if (!rb->strcmp(file_pt[entries], pname))
157 curfile = entries;
158 entries++;
160 buf += (sizeof(char**));
161 buf_size -= (sizeof(char**));
166 static int change_filename(int direct)
168 bool file_erased = (file_pt[curfile] == NULL);
169 direction = direct;
171 curfile += (direct == DIR_PREV? entries - 1: 1);
172 if (curfile >= entries)
173 curfile -= entries;
175 if (file_erased)
177 /* remove 'erased' file names from list. */
178 int count, i;
179 for (count = i = 0; i < entries; i++)
181 if (curfile == i)
182 curfile = count;
183 if (file_pt[i] != NULL)
184 file_pt[count++] = file_pt[i];
186 entries = count;
189 if (entries == 0)
191 rb->splash(HZ, "No supported files");
192 return PLUGIN_ERROR;
195 rb->strcpy(rb->strrchr(np_file, '/')+1, file_pt[curfile]);
197 return PLUGIN_OTHER;
200 /* switch off overlay, for handling SYS_ events */
201 static void cleanup(void *parameter)
203 (void)parameter;
204 #ifdef USEGSLIB
205 grey_show(false);
206 #endif
209 #ifdef HAVE_LCD_COLOR
210 static bool set_option_grayscale(void)
212 bool gray = settings.jpeg_colour_mode == COLOURMODE_GRAY;
213 rb->set_bool("Grayscale (Jpeg)", &gray);
214 settings.jpeg_colour_mode = gray ? COLOURMODE_GRAY : COLOURMODE_COLOUR;
215 return false;
218 static bool set_option_dithering(void)
220 static const struct opt_items dithering[DITHER_NUM_MODES] = {
221 [DITHER_NONE] = { "Off", -1 },
222 [DITHER_ORDERED] = { "Ordered", -1 },
223 [DITHER_DIFFUSION] = { "Diffusion", -1 },
226 rb->set_option("Dithering (Jpeg)", &settings.jpeg_dither_mode, INT,
227 dithering, DITHER_NUM_MODES, NULL);
228 return false;
231 MENUITEM_FUNCTION(grayscale_item, 0, "Greyscale (Jpeg)",
232 set_option_grayscale, NULL, NULL, Icon_NOICON);
233 MENUITEM_FUNCTION(dithering_item, 0, "Dithering (Jpeg)",
234 set_option_dithering, NULL, NULL, Icon_NOICON);
235 MAKE_MENU(display_menu, "Display Options", NULL, Icon_NOICON,
236 &grayscale_item, &dithering_item);
238 static void display_options(void)
240 rb->do_menu(&display_menu, NULL, NULL, false);
242 #endif /* HAVE_LCD_COLOR */
244 static int show_menu(void) /* return 1 to quit */
246 int result;
248 enum menu_id
250 MIID_RETURN = 0,
251 MIID_TOGGLE_SS_MODE,
252 MIID_CHANGE_SS_MODE,
253 #ifdef USE_PLUG_BUF
254 MIID_SHOW_PLAYBACK_MENU,
255 #endif
256 #ifdef HAVE_LCD_COLOR
257 MIID_DISPLAY_OPTIONS,
258 #endif
259 MIID_QUIT,
262 MENUITEM_STRINGLIST(menu, "Image Viewer Menu", NULL,
263 "Return", "Toggle Slideshow Mode",
264 "Change Slideshow Time",
265 #ifdef USE_PLUG_BUF
266 "Show Playback Menu",
267 #endif
268 #ifdef HAVE_LCD_COLOR
269 "Display Options",
270 #endif
271 "Quit");
273 static const struct opt_items slideshow[2] = {
274 { "Disable", -1 },
275 { "Enable", -1 },
278 result=rb->do_menu(&menu, NULL, NULL, false);
280 switch (result)
282 case MIID_RETURN:
283 break;
284 case MIID_TOGGLE_SS_MODE:
285 rb->set_option("Toggle Slideshow", &iv_api.slideshow_enabled, BOOL,
286 slideshow , 2, NULL);
287 break;
288 case MIID_CHANGE_SS_MODE:
289 rb->set_int("Slideshow Time", "s", UNIT_SEC,
290 &settings.ss_timeout, NULL, 1,
291 SS_MIN_TIMEOUT, SS_MAX_TIMEOUT, NULL);
292 break;
294 #ifdef USE_PLUG_BUF
295 case MIID_SHOW_PLAYBACK_MENU:
296 if (iv_api.plug_buf)
298 playback_control(NULL);
300 else
302 rb->splash(HZ, "Cannot restart playback");
304 break;
305 #endif
306 #ifdef HAVE_LCD_COLOR
307 case MIID_DISPLAY_OPTIONS:
308 display_options();
309 break;
310 #endif
311 case MIID_QUIT:
312 return 1;
313 break;
316 #ifdef DISK_SPINDOWN
317 /* change ata spindown time based on slideshow time setting */
318 iv_api.immediate_ata_off = false;
319 rb->storage_spindown(rb->global_settings->disk_spindown);
321 if (iv_api.slideshow_enabled)
323 if(settings.ss_timeout < 10)
325 /* slideshow times < 10s keep disk spinning */
326 rb->storage_spindown(0);
328 else if (!rb->mp3_is_playing())
330 /* slideshow times > 10s and not playing: ata_off after load */
331 iv_api.immediate_ata_off = true;
334 #endif
335 #if LCD_DEPTH > 1
336 rb->lcd_set_backdrop(NULL);
337 rb->lcd_set_foreground(LCD_WHITE);
338 rb->lcd_set_background(LCD_BLACK);
339 #endif
340 rb->lcd_clear_display();
341 return 0;
344 #ifdef USE_PLUG_BUF
345 static int ask_and_get_audio_buffer(const char *filename)
347 rb->lcd_setfont(FONT_SYSFIXED);
348 rb->lcd_clear_display();
349 rb->lcd_puts(0, 0, rb->strrchr(filename,'/')+1);
350 rb->lcd_puts(0, 1, "Not enough plugin memory!");
351 rb->lcd_puts(0, 2, "Zoom In: Stop playback.");
352 if(entries > 1)
353 rb->lcd_puts(0, 3, "Left/Right: Skip File.");
354 rb->lcd_puts(0, 4, "Show Menu: Quit.");
355 rb->lcd_update();
356 rb->lcd_setfont(FONT_UI);
358 rb->button_clear_queue();
360 while (1)
362 int button = rb->button_get(true);
363 switch(button)
365 case IMGVIEW_ZOOM_IN:
366 iv_api.plug_buf = false;
367 buf = rb->plugin_get_audio_buffer(&buf_size);
368 /*try again this file, now using the audio buffer */
369 return PLUGIN_OTHER;
370 #ifdef IMGVIEW_RC_MENU
371 case IMGVIEW_RC_MENU:
372 #endif
373 #ifdef IMGVIEW_QUIT
374 case IMGVIEW_QUIT:
375 #endif
376 case IMGVIEW_MENU:
377 return PLUGIN_OK;
379 case IMGVIEW_LEFT:
380 if(entries>1)
382 rb->lcd_clear_display();
383 return change_filename(DIR_PREV);
385 break;
387 case IMGVIEW_RIGHT:
388 if(entries>1)
390 rb->lcd_clear_display();
391 return change_filename(DIR_NEXT);
393 break;
394 default:
395 if(rb->default_event_handler_ex(button, cleanup, NULL)
396 == SYS_USB_CONNECTED)
397 return PLUGIN_USB_CONNECTED;
401 #endif /* USE_PLUG_BUF */
403 /* callback updating a progress meter while image decoding */
404 static void cb_progress(int current, int total)
406 rb->yield(); /* be nice to the other threads */
407 #ifndef USEGSLIB
408 /* in slideshow mode, keep gui interference to a minimum */
409 const int size = (!iv_api.running_slideshow ? 8 : 4);
410 #else
411 const int size = 8;
412 if(!iv_api.running_slideshow)
413 #endif
415 rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN],
416 0, LCD_HEIGHT-size, LCD_WIDTH, size,
417 total, 0, current, HORIZONTAL);
418 rb->lcd_update_rect(0, LCD_HEIGHT-size, LCD_WIDTH, size);
422 #define VSCROLL (LCD_HEIGHT/8)
423 #define HSCROLL (LCD_WIDTH/10)
425 /* Pan the viewing window right - move image to the left and fill in
426 the right-hand side */
427 static void pan_view_right(struct image_info *info)
429 int move;
431 move = MIN(HSCROLL, info->width - info->x - LCD_WIDTH);
432 if (move > 0)
434 mylcd_ub_scroll_left(move); /* scroll left */
435 info->x += move;
436 imgdec->draw_image_rect(info, LCD_WIDTH - move, 0,
437 move, info->height-info->y);
438 mylcd_ub_update();
442 /* Pan the viewing window left - move image to the right and fill in
443 the left-hand side */
444 static void pan_view_left(struct image_info *info)
446 int move;
448 move = MIN(HSCROLL, info->x);
449 if (move > 0)
451 mylcd_ub_scroll_right(move); /* scroll right */
452 info->x -= move;
453 imgdec->draw_image_rect(info, 0, 0, move, info->height-info->y);
454 mylcd_ub_update();
458 /* Pan the viewing window up - move image down and fill in
459 the top */
460 static void pan_view_up(struct image_info *info)
462 int move;
464 move = MIN(VSCROLL, info->y);
465 if (move > 0)
467 mylcd_ub_scroll_down(move); /* scroll down */
468 info->y -= move;
469 #ifdef HAVE_LCD_COLOR
470 if (image_type == IMAGE_JPEG
471 && settings.jpeg_dither_mode == DITHER_DIFFUSION)
473 /* Draw over the band at the top of the last update
474 caused by lack of error history on line zero. */
475 move = MIN(move + 1, info->y + info->height);
477 #endif
478 imgdec->draw_image_rect(info, 0, 0, info->width-info->x, move);
479 mylcd_ub_update();
483 /* Pan the viewing window down - move image up and fill in
484 the bottom */
485 static void pan_view_down(struct image_info *info)
487 int move;
489 move = MIN(VSCROLL, info->height - info->y - LCD_HEIGHT);
490 if (move > 0)
492 mylcd_ub_scroll_up(move); /* scroll up */
493 info->y += move;
494 #ifdef HAVE_LCD_COLOR
495 if (image_type == IMAGE_JPEG
496 && settings.jpeg_dither_mode == DITHER_DIFFUSION)
498 /* Save the line that was on the last line of the display
499 and draw one extra line above then recover the line with
500 image data that had an error history when it was drawn.
502 move++, info->y--;
503 rb->memcpy(rgb_linebuf,
504 rb->lcd_framebuffer + (LCD_HEIGHT - move)*LCD_WIDTH,
505 LCD_WIDTH*sizeof (fb_data));
507 #endif
509 imgdec->draw_image_rect(info, 0, LCD_HEIGHT - move,
510 info->width-info->x, move);
512 #ifdef HAVE_LCD_COLOR
513 if (image_type == IMAGE_JPEG
514 && settings.jpeg_dither_mode == DITHER_DIFFUSION)
516 /* Cover the first row drawn with previous image data. */
517 rb->memcpy(rb->lcd_framebuffer + (LCD_HEIGHT - move)*LCD_WIDTH,
518 rgb_linebuf, LCD_WIDTH*sizeof (fb_data));
519 info->y++;
521 #endif
522 mylcd_ub_update();
526 /* interactively scroll around the image */
527 static int scroll_bmp(struct image_info *info)
529 int button;
530 int lastbutton = BUTTON_NONE;
532 while (true)
534 if (iv_api.slideshow_enabled)
535 button = rb->button_get_w_tmo(settings.ss_timeout * HZ);
536 else
537 button = rb->button_get(true);
539 iv_api.running_slideshow = false;
541 switch(button)
543 case IMGVIEW_LEFT:
544 if (entries > 1 && info->width <= LCD_WIDTH
545 && info->height <= LCD_HEIGHT)
546 return change_filename(DIR_PREV);
547 case IMGVIEW_LEFT | BUTTON_REPEAT:
548 pan_view_left(info);
549 break;
551 case IMGVIEW_RIGHT:
552 if (entries > 1 && info->width <= LCD_WIDTH
553 && info->height <= LCD_HEIGHT)
554 return change_filename(DIR_NEXT);
555 case IMGVIEW_RIGHT | BUTTON_REPEAT:
556 pan_view_right(info);
557 break;
559 case IMGVIEW_UP:
560 case IMGVIEW_UP | BUTTON_REPEAT:
561 pan_view_up(info);
562 break;
564 case IMGVIEW_DOWN:
565 case IMGVIEW_DOWN | BUTTON_REPEAT:
566 pan_view_down(info);
567 break;
569 case BUTTON_NONE:
570 if (iv_api.slideshow_enabled && entries > 1)
572 iv_api.running_slideshow = true;
573 return change_filename(DIR_NEXT);
575 break;
577 #ifdef IMGVIEW_SLIDE_SHOW
578 case IMGVIEW_SLIDE_SHOW:
579 iv_api.slideshow_enabled = !iv_api.slideshow_enabled;
580 break;
581 #endif
583 #ifdef IMGVIEW_NEXT_REPEAT
584 case IMGVIEW_NEXT_REPEAT:
585 #endif
586 case IMGVIEW_NEXT:
587 if (entries > 1)
588 return change_filename(DIR_NEXT);
589 break;
591 #ifdef IMGVIEW_PREVIOUS_REPEAT
592 case IMGVIEW_PREVIOUS_REPEAT:
593 #endif
594 case IMGVIEW_PREVIOUS:
595 if (entries > 1)
596 return change_filename(DIR_PREV);
597 break;
599 case IMGVIEW_ZOOM_IN:
600 #ifdef IMGVIEW_ZOOM_PRE
601 if (lastbutton != IMGVIEW_ZOOM_PRE)
602 break;
603 #endif
604 return ZOOM_IN;
605 break;
607 case IMGVIEW_ZOOM_OUT:
608 #ifdef IMGVIEW_ZOOM_PRE
609 if (lastbutton != IMGVIEW_ZOOM_PRE)
610 break;
611 #endif
612 return ZOOM_OUT;
613 break;
615 #ifdef IMGVIEW_RC_MENU
616 case IMGVIEW_RC_MENU:
617 #endif
618 case IMGVIEW_MENU:
619 #ifdef IMGVIEW_MENU_PRE
620 if (lastbutton != IMGVIEW_MENU_PRE)
621 break;
622 #endif
623 #ifdef USEGSLIB
624 grey_show(false); /* switch off greyscale overlay */
625 #endif
626 if (show_menu() == 1)
627 return PLUGIN_OK;
629 #ifdef USEGSLIB
630 grey_show(true); /* switch on greyscale overlay */
631 #else
632 imgdec->draw_image_rect(info, 0, 0,
633 info->width-info->x, info->height-info->y);
634 mylcd_ub_update();
635 #endif
636 break;
638 #ifdef IMGVIEW_QUIT
639 case IMGVIEW_QUIT:
640 return PLUGIN_OK;
641 break;
642 #endif
644 default:
645 if (rb->default_event_handler_ex(button, cleanup, NULL)
646 == SYS_USB_CONNECTED)
647 return PLUGIN_USB_CONNECTED;
648 break;
650 } /* switch */
652 if (button != BUTTON_NONE)
653 lastbutton = button;
654 } /* while (true) */
657 /********************* main function *************************/
659 /* how far can we zoom in without running out of memory */
660 static int min_downscale(int bufsize)
662 int downscale = 8;
664 if (imgdec->img_mem(8) > bufsize)
665 return 0; /* error, too large, even 1:8 doesn't fit */
667 while (downscale > 1 && imgdec->img_mem(downscale/2) <= bufsize)
668 downscale /= 2;
670 return downscale;
673 /* how far can we zoom out, to fit image into the LCD */
674 static int max_downscale(struct image_info *info)
676 int downscale = 1;
678 while (downscale < 8 && (info->x_size/downscale > LCD_WIDTH
679 || info->y_size/downscale > LCD_HEIGHT))
681 downscale *= 2;
684 return downscale;
687 /* set the view to the given center point, limit if necessary */
688 static void set_view(struct image_info *info, int cx, int cy)
690 int x, y;
692 /* plain center to available width/height */
693 x = cx - MIN(LCD_WIDTH, info->width) / 2;
694 y = cy - MIN(LCD_HEIGHT, info->height) / 2;
696 /* limit against upper image size */
697 x = MIN(info->width - LCD_WIDTH, x);
698 y = MIN(info->height - LCD_HEIGHT, y);
700 /* limit against negative side */
701 x = MAX(0, x);
702 y = MAX(0, y);
704 info->x = x; /* set the values */
705 info->y = y;
708 /* calculate the view center based on the bitmap position */
709 static void get_view(struct image_info *info, int *p_cx, int *p_cy)
711 *p_cx = info->x + MIN(LCD_WIDTH, info->width) / 2;
712 *p_cy = info->y + MIN(LCD_HEIGHT, info->height) / 2;
715 /* load, decode, display the image */
716 static int load_and_show(char* filename, struct image_info *info)
718 int status;
719 int cx, cy;
720 ssize_t remaining;
722 rb->lcd_clear_display();
724 status = get_image_type(filename);
725 if (image_type != status) /* type of image is changed, load decoder. */
727 struct loader_info loader_info = {
728 status, &iv_api, decoder_buf, decoder_buf_size,
730 image_type = status;
731 imgdec = load_decoder(&loader_info);
732 if (imgdec == NULL)
734 /* something is wrong */
735 return PLUGIN_ERROR;
737 #ifdef USE_PLUG_BUF
738 if(iv_api.plug_buf)
740 buf = loader_info.buffer;
741 buf_size = loader_info.size;
743 #endif
745 rb->memset(info, 0, sizeof(*info));
746 remaining = buf_size;
748 if (rb->button_get(false) == IMGVIEW_MENU)
749 status = PLUGIN_ABORT;
750 else
751 status = imgdec->load_image(filename, info, buf, &remaining);
753 if (status == PLUGIN_OUTOFMEM)
755 #ifdef USE_PLUG_BUF
756 if(iv_api.plug_buf)
758 return ask_and_get_audio_buffer(filename);
760 else
761 #endif
763 rb->splash(HZ, "Out of Memory");
764 file_pt[curfile] = NULL;
765 return change_filename(direction);
768 else if (status == PLUGIN_ERROR)
770 file_pt[curfile] = NULL;
771 return change_filename(direction);
773 else if (status == PLUGIN_ABORT) {
774 rb->splash(HZ, "aborted");
775 return PLUGIN_OK;
778 ds_max = max_downscale(info); /* check display constraint */
779 ds_min = min_downscale(remaining); /* check memory constraint */
780 if (ds_min == 0)
782 if (imgdec->unscaled_avail)
784 /* Can not resize the image but original one is available, so use it. */
785 ds_min = ds_max = 1;
787 else
788 #ifdef USE_PLUG_BUF
789 if (iv_api.plug_buf)
791 return ask_and_get_audio_buffer(filename);
793 else
794 #endif
796 rb->splash(HZ, "too large");
797 file_pt[curfile] = NULL;
798 return change_filename(direction);
801 else if (ds_max < ds_min)
802 ds_max = ds_min;
804 ds = ds_max; /* initialize setting */
805 cx = info->x_size/ds/2; /* center the view */
806 cy = info->y_size/ds/2;
808 do /* loop the image prepare and decoding when zoomed */
810 status = imgdec->get_image(info, ds); /* decode or fetch from cache */
811 if (status == PLUGIN_ERROR)
813 file_pt[curfile] = NULL;
814 return change_filename(direction);
817 set_view(info, cx, cy);
819 if(!iv_api.running_slideshow)
821 rb->lcd_putsf(0, 3, "showing %dx%d", info->width, info->height);
822 rb->lcd_update();
825 mylcd_ub_clear_display();
826 imgdec->draw_image_rect(info, 0, 0,
827 info->width-info->x, info->height-info->y);
828 mylcd_ub_update();
830 #ifdef USEGSLIB
831 grey_show(true); /* switch on greyscale overlay */
832 #endif
834 /* drawing is now finished, play around with scrolling
835 * until you press OFF or connect USB
837 while (1)
839 status = scroll_bmp(info);
840 if (status == ZOOM_IN)
842 if (ds > ds_min || (imgdec->unscaled_avail && ds > 1))
844 /* if 1/1 is always available, jump ds from ds_min to 1. */
845 int zoom = (ds == ds_min)? ds_min: 2;
846 ds /= zoom; /* reduce downscaling to zoom in */
847 get_view(info, &cx, &cy);
848 cx *= zoom; /* prepare the position in the new image */
849 cy *= zoom;
851 else
852 continue;
855 if (status == ZOOM_OUT)
857 if (ds < ds_max)
859 /* if ds is 1 and ds_min is > 1, jump ds to ds_min. */
860 int zoom = (ds < ds_min)? ds_min: 2;
861 ds *= zoom; /* increase downscaling to zoom out */
862 get_view(info, &cx, &cy);
863 cx /= zoom; /* prepare the position in the new image */
864 cy /= zoom;
866 else
867 continue;
869 break;
872 #ifdef USEGSLIB
873 grey_show(false); /* switch off overlay */
874 #endif
875 rb->lcd_clear_display();
877 while (status > PLUGIN_OTHER);
878 #ifdef USEGSLIB
879 rb->lcd_update();
880 #endif
881 return status;
884 /******************** Plugin entry point *********************/
886 enum plugin_status plugin_start(const void* parameter)
888 int condition;
889 #ifdef USEGSLIB
890 long greysize; /* helper */
891 #endif
893 if(!parameter) return PLUGIN_ERROR;
895 rb->strcpy(np_file, parameter);
896 if (get_image_type(np_file) == IMAGE_UNKNOWN)
898 rb->splash(HZ*2, "Unsupported file");
899 return PLUGIN_ERROR;
902 #ifdef USE_PLUG_BUF
903 buf = rb->plugin_get_buffer(&buf_size);
904 #else
905 decoder_buf = rb->plugin_get_buffer(&decoder_buf_size);
906 buf = rb->plugin_get_audio_buffer(&buf_size);
907 #endif
909 get_pic_list();
911 if(!entries) return PLUGIN_ERROR;
913 #ifdef USEGSLIB
914 if (!grey_init(buf, buf_size, GREY_ON_COP,
915 LCD_WIDTH, LCD_HEIGHT, &greysize))
917 rb->splash(HZ, "grey buf error");
918 return PLUGIN_ERROR;
920 buf += greysize;
921 buf_size -= greysize;
922 #endif
924 #ifdef USE_PLUG_BUF
925 decoder_buf = buf;
926 decoder_buf_size = buf_size;
927 if(!rb->audio_status())
929 iv_api.plug_buf = false;
930 buf = rb->plugin_get_audio_buffer(&buf_size);
932 #endif
934 /* should be ok to just load settings since the plugin itself has
935 just been loaded from disk and the drive should be spinning */
936 configfile_load(IMGVIEW_CONFIGFILE, config,
937 ARRAYLEN(config), IMGVIEW_SETTINGS_MINVERSION);
938 rb->memcpy(&old_settings, &settings, sizeof (settings));
940 /* Turn off backlight timeout */
941 backlight_force_on(); /* backlight control in lib/helper.c */
943 #if LCD_DEPTH > 1
944 rb->lcd_set_backdrop(NULL);
945 rb->lcd_set_foreground(LCD_WHITE);
946 rb->lcd_set_background(LCD_BLACK);
947 #endif
951 condition = load_and_show(np_file, &image_info);
952 } while (condition >= PLUGIN_OTHER);
953 release_decoder();
955 if (rb->memcmp(&settings, &old_settings, sizeof (settings)))
957 /* Just in case drive has to spin, keep it from looking locked */
958 rb->splash(0, "Saving Settings");
959 configfile_save(IMGVIEW_CONFIGFILE, config,
960 ARRAYLEN(config), IMGVIEW_SETTINGS_VERSION);
963 #ifdef DISK_SPINDOWN
964 /* set back ata spindown time in case we changed it */
965 rb->storage_spindown(rb->global_settings->disk_spindown);
966 #endif
968 /* Turn on backlight timeout (revert to settings) */
969 backlight_use_settings(); /* backlight control in lib/helper.c */
971 #ifdef USEGSLIB
972 grey_release(); /* deinitialize */
973 #endif
975 return condition;