jpeg,png: Merge user interface code and plugin entry point of the two plugins (part...
[kugel-rb.git] / apps / plugins / imageviewer / imageviewer.c
blob1b39c5a9e318ba208dcc7c3349b5f9a76e4d643d
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * user intereface of image viewers (jpeg, png, etc.)
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 ****************************************************************************/
22 #include "plugin.h"
23 #include <lib/playback_control.h>
24 #include <lib/helper.h>
25 #include <lib/configfile.h>
26 #include "imageviewer.h"
28 PLUGIN_HEADER
30 #ifdef USEGSLIB
31 GREY_INFO_STRUCT
32 #endif
34 /* Headings */
35 #define DIR_PREV 1
36 #define DIR_NEXT -1
37 #define DIR_NONE 0
39 /******************************* Globals ***********************************/
41 bool slideshow_enabled = false; /* run slideshow */
42 bool running_slideshow = false; /* loading image because of slideshw */
43 #ifdef DISK_SPINDOWN
44 bool immediate_ata_off = false; /* power down disk after loading */
45 #endif
46 #if PLUGIN_BUFFER_SIZE >= MIN_MEM
47 /* are we using the plugin buffer or the audio buffer? */
48 bool plug_buf = true;
49 #endif
51 /* Persistent configuration */
52 #define IMGVIEW_CONFIGFILE "imageviewer.cfg"
53 #define IMGVIEW_SETTINGS_MINVERSION 1
54 #define IMGVIEW_SETTINGS_VERSION 2
56 /* Slideshow times */
57 #define SS_MIN_TIMEOUT 1
58 #define SS_MAX_TIMEOUT 20
59 #define SS_DEFAULT_TIMEOUT 5
61 #ifdef HAVE_LCD_COLOR
62 /* needed for value of settings */
63 #include "jpeg/yuv2rgb.h"
64 #endif
66 /* jpeg use this */
67 struct imgview_settings settings =
69 #ifdef HAVE_LCD_COLOR
70 COLOURMODE_COLOUR,
71 DITHER_NONE,
72 #endif
73 SS_DEFAULT_TIMEOUT
75 static struct imgview_settings old_settings;
77 static struct configdata config[] =
79 #ifdef HAVE_LCD_COLOR
80 { TYPE_ENUM, 0, COLOUR_NUM_MODES, { .int_p = &settings.jpeg_colour_mode },
81 "Colour Mode", (char *[]){ "Colour", "Grayscale" } },
82 { TYPE_ENUM, 0, DITHER_NUM_MODES, { .int_p = &settings.jpeg_dither_mode },
83 "Dither Mode", (char *[]){ "None", "Ordered", "Diffusion" } },
84 #endif
85 { TYPE_INT, SS_MIN_TIMEOUT, SS_MAX_TIMEOUT,
86 { .int_p = &settings.ss_timeout }, "Slideshow Time", NULL },
89 #if LCD_DEPTH > 1
90 static fb_data* old_backdrop;
91 #endif
93 /**************** begin Application ********************/
96 /************************* Globals ***************************/
98 #if defined(HAVE_LCD_COLOR) && defined(JPEG_VIEWER)
99 static fb_data rgb_linebuf[LCD_WIDTH]; /* Line buffer for scrolling when
100 DITHER_DIFFUSION is set */
101 #endif
103 /* my memory pool (from the mp3 buffer) */
104 static char print[32]; /* use a common snprintf() buffer */
105 /* the remaining free part of the buffer for loaded+resized images */
106 static unsigned char* buf;
107 static ssize_t buf_size;
109 static int ds, ds_min, ds_max; /* downscaling and limits */
110 static struct image_info image_info;
112 static struct tree_context *tree;
114 /* the current full file name */
115 static char np_file[MAX_PATH];
116 static int curfile = 0, direction = DIR_NONE, entries = 0;
118 /* list of the supported image files */
119 static char **file_pt;
121 /************************* Implementation ***************************/
123 /*Read directory contents for scrolling. */
124 static void get_pic_list(void)
126 int i;
127 struct entry *dircache;
128 char *pname;
129 tree = rb->tree_get_context();
130 dircache = tree->dircache;
132 file_pt = (char **) buf;
134 /* Remove path and leave only the name.*/
135 pname = rb->strrchr(np_file,'/');
136 pname++;
138 for (i = 0; i < tree->filesindir; i++)
140 if (!(dircache[i].attr & ATTR_DIRECTORY)
141 && img_ext(rb->strrchr(dircache[i].name,'.')))
143 file_pt[entries] = dircache[i].name;
144 /* Set Selected File. */
145 if (!rb->strcmp(file_pt[entries], pname))
146 curfile = entries;
147 entries++;
151 buf += (entries * sizeof(char**));
152 buf_size -= (entries * sizeof(char**));
155 static int change_filename(int direct)
157 bool file_erased = (file_pt[curfile] == NULL);
158 direction = direct;
160 curfile += (direct == DIR_PREV? entries - 1: 1);
161 if (curfile >= entries)
162 curfile -= entries;
164 if (file_erased)
166 /* remove 'erased' file names from list. */
167 int count, i;
168 for (count = i = 0; i < entries; i++)
170 if (curfile == i)
171 curfile = count;
172 if (file_pt[i] != NULL)
173 file_pt[count++] = file_pt[i];
175 entries = count;
178 if (entries == 0)
180 rb->splash(HZ, "No supported files");
181 return PLUGIN_ERROR;
184 if (rb->strlen(tree->currdir) > 1)
186 rb->strcpy(np_file, tree->currdir);
187 rb->strcat(np_file, "/");
189 else
190 rb->strcpy(np_file, tree->currdir);
192 rb->strcat(np_file, file_pt[curfile]);
194 return PLUGIN_OTHER;
197 /* switch off overlay, for handling SYS_ events */
198 static void cleanup(void *parameter)
200 (void)parameter;
201 #ifdef USEGSLIB
202 grey_show(false);
203 #endif
206 #define VSCROLL (LCD_HEIGHT/8)
207 #define HSCROLL (LCD_WIDTH/10)
209 #define ZOOM_IN 100 /* return codes for below function */
210 #define ZOOM_OUT 101
212 #if defined(HAVE_LCD_COLOR) && defined(JPEG_VIEWER)
213 static bool set_option_grayscale(void)
215 bool gray = settings.jpeg_colour_mode == COLOURMODE_GRAY;
216 rb->set_bool("Grayscale", &gray);
217 settings.jpeg_colour_mode = gray ? COLOURMODE_GRAY : COLOURMODE_COLOUR;
218 return false;
221 static bool set_option_dithering(void)
223 static const struct opt_items dithering[DITHER_NUM_MODES] = {
224 [DITHER_NONE] = { "Off", -1 },
225 [DITHER_ORDERED] = { "Ordered", -1 },
226 [DITHER_DIFFUSION] = { "Diffusion", -1 },
229 rb->set_option("Dithering", &settings.jpeg_dither_mode, INT,
230 dithering, DITHER_NUM_MODES, NULL);
231 return false;
234 MENUITEM_FUNCTION(grayscale_item, 0, "Greyscale",
235 set_option_grayscale, NULL, NULL, Icon_NOICON);
236 MENUITEM_FUNCTION(dithering_item, 0, "Dithering",
237 set_option_dithering, NULL, NULL, Icon_NOICON);
238 MAKE_MENU(display_menu, "Display Options", NULL, Icon_NOICON,
239 &grayscale_item, &dithering_item);
241 static void display_options(void)
243 rb->do_menu(&display_menu, NULL, NULL, false);
245 #endif /* defined(HAVE_LCD_COLOR) && defined(JPEG_VIEWER) */
247 static int show_menu(void) /* return 1 to quit */
249 #if LCD_DEPTH > 1
250 rb->lcd_set_backdrop(old_backdrop);
251 #ifdef HAVE_LCD_COLOR
252 rb->lcd_set_foreground(rb->global_settings->fg_color);
253 rb->lcd_set_background(rb->global_settings->bg_color);
254 #else
255 rb->lcd_set_foreground(LCD_BLACK);
256 rb->lcd_set_background(LCD_WHITE);
257 #endif
258 #endif
259 int result;
261 enum menu_id
263 MIID_RETURN = 0,
264 MIID_TOGGLE_SS_MODE,
265 MIID_CHANGE_SS_MODE,
266 #if PLUGIN_BUFFER_SIZE >= MIN_MEM
267 MIID_SHOW_PLAYBACK_MENU,
268 #endif
269 #if defined(HAVE_LCD_COLOR) && defined(JPEG_VIEWER)
270 MIID_DISPLAY_OPTIONS,
271 #endif
272 MIID_QUIT,
275 MENUITEM_STRINGLIST(menu, MENU_TITLE, NULL,
276 "Return", "Toggle Slideshow Mode",
277 "Change Slideshow Time",
278 #if PLUGIN_BUFFER_SIZE >= MIN_MEM
279 "Show Playback Menu",
280 #endif
281 #if defined(HAVE_LCD_COLOR) && defined(JPEG_VIEWER)
282 "Display Options",
283 #endif
284 "Quit");
286 static const struct opt_items slideshow[2] = {
287 { "Disable", -1 },
288 { "Enable", -1 },
291 result=rb->do_menu(&menu, NULL, NULL, false);
293 switch (result)
295 case MIID_RETURN:
296 break;
297 case MIID_TOGGLE_SS_MODE:
298 rb->set_option("Toggle Slideshow", &slideshow_enabled, INT,
299 slideshow , 2, NULL);
300 break;
301 case MIID_CHANGE_SS_MODE:
302 rb->set_int("Slideshow Time", "s", UNIT_SEC,
303 &settings.ss_timeout, NULL, 1,
304 SS_MIN_TIMEOUT, SS_MAX_TIMEOUT, NULL);
305 break;
307 #if PLUGIN_BUFFER_SIZE >= MIN_MEM
308 case MIID_SHOW_PLAYBACK_MENU:
309 if (plug_buf)
311 playback_control(NULL);
313 else
315 rb->splash(HZ, "Cannot restart playback");
317 break;
318 #endif
319 #if defined(HAVE_LCD_COLOR) && defined(JPEG_VIEWER)
320 case MIID_DISPLAY_OPTIONS:
321 display_options();
322 break;
323 #endif
324 case MIID_QUIT:
325 return 1;
326 break;
329 #ifdef DISK_SPINDOWN
330 /* change ata spindown time based on slideshow time setting */
331 immediate_ata_off = false;
332 rb->storage_spindown(rb->global_settings->disk_spindown);
334 if (slideshow_enabled)
336 if(settings.ss_timeout < 10)
338 /* slideshow times < 10s keep disk spinning */
339 rb->storage_spindown(0);
341 else if (!rb->mp3_is_playing())
343 /* slideshow times > 10s and not playing: ata_off after load */
344 immediate_ata_off = true;
347 #endif
348 #if LCD_DEPTH > 1
349 rb->lcd_set_backdrop(NULL);
350 rb->lcd_set_foreground(LCD_WHITE);
351 rb->lcd_set_background(LCD_BLACK);
352 #endif
353 rb->lcd_clear_display();
354 return 0;
357 /* Pan the viewing window right - move image to the left and fill in
358 the right-hand side */
359 static void pan_view_right(struct image_info *info)
361 int move;
363 move = MIN(HSCROLL, info->width - info->x - LCD_WIDTH);
364 if (move > 0)
366 MYXLCD(scroll_left)(move); /* scroll left */
367 info->x += move;
368 draw_image_rect(info, LCD_WIDTH - move, 0, move, info->height-info->y);
369 MYLCD_UPDATE();
373 /* Pan the viewing window left - move image to the right and fill in
374 the left-hand side */
375 static void pan_view_left(struct image_info *info)
377 int move;
379 move = MIN(HSCROLL, info->x);
380 if (move > 0)
382 MYXLCD(scroll_right)(move); /* scroll right */
383 info->x -= move;
384 draw_image_rect(info, 0, 0, move, info->height-info->y);
385 MYLCD_UPDATE();
389 /* Pan the viewing window up - move image down and fill in
390 the top */
391 static void pan_view_up(struct image_info *info)
393 int move;
395 move = MIN(VSCROLL, info->y);
396 if (move > 0)
398 MYXLCD(scroll_down)(move); /* scroll down */
399 info->y -= move;
400 #if defined(HAVE_LCD_COLOR) && defined(JPEG_VIEWER)
401 if (settings.jpeg_dither_mode == DITHER_DIFFUSION)
403 /* Draw over the band at the top of the last update
404 caused by lack of error history on line zero. */
405 move = MIN(move + 1, info->y + info->height);
407 #endif
408 draw_image_rect(info, 0, 0, info->width-info->x, move);
409 MYLCD_UPDATE();
413 /* Pan the viewing window down - move image up and fill in
414 the bottom */
415 static void pan_view_down(struct image_info *info)
417 int move;
419 move = MIN(VSCROLL, info->height - info->y - LCD_HEIGHT);
420 if (move > 0)
422 MYXLCD(scroll_up)(move); /* scroll up */
423 info->y += move;
424 #if defined(HAVE_LCD_COLOR) && defined(JPEG_VIEWER)
425 if (settings.jpeg_dither_mode == DITHER_DIFFUSION)
427 /* Save the line that was on the last line of the display
428 and draw one extra line above then recover the line with
429 image data that had an error history when it was drawn.
431 move++, info->y--;
432 rb->memcpy(rgb_linebuf,
433 rb->lcd_framebuffer + (LCD_HEIGHT - move)*LCD_WIDTH,
434 LCD_WIDTH*sizeof (fb_data));
436 #endif
438 draw_image_rect(info, 0, LCD_HEIGHT - move, info->width-info->x, move);
440 #if defined(HAVE_LCD_COLOR) && defined(JPEG_VIEWER)
441 if (settings.jpeg_dither_mode == DITHER_DIFFUSION)
443 /* Cover the first row drawn with previous image data. */
444 rb->memcpy(rb->lcd_framebuffer + (LCD_HEIGHT - move)*LCD_WIDTH,
445 rgb_linebuf, LCD_WIDTH*sizeof (fb_data));
446 info->y++;
448 #endif
449 MYLCD_UPDATE();
453 /* interactively scroll around the image */
454 static int scroll_bmp(struct image_info *info)
456 int button;
457 int lastbutton = 0;
459 while (true)
461 if (slideshow_enabled)
462 button = rb->button_get_w_tmo(settings.ss_timeout * HZ);
463 else
464 button = rb->button_get(true);
466 running_slideshow = false;
468 switch(button)
470 case IMGVIEW_LEFT:
471 if (entries > 1 && info->width <= LCD_WIDTH
472 && info->height <= LCD_HEIGHT)
473 return change_filename(DIR_PREV);
474 case IMGVIEW_LEFT | BUTTON_REPEAT:
475 pan_view_left(info);
476 break;
478 case IMGVIEW_RIGHT:
479 if (entries > 1 && info->width <= LCD_WIDTH
480 && info->height <= LCD_HEIGHT)
481 return change_filename(DIR_NEXT);
482 case IMGVIEW_RIGHT | BUTTON_REPEAT:
483 pan_view_right(info);
484 break;
486 case IMGVIEW_UP:
487 case IMGVIEW_UP | BUTTON_REPEAT:
488 pan_view_up(info);
489 break;
491 case IMGVIEW_DOWN:
492 case IMGVIEW_DOWN | BUTTON_REPEAT:
493 pan_view_down(info);
494 break;
496 case BUTTON_NONE:
497 if (!slideshow_enabled)
498 break;
499 running_slideshow = true;
500 if (entries > 1)
501 return change_filename(DIR_NEXT);
502 break;
504 #ifdef IMGVIEW_SLIDE_SHOW
505 case IMGVIEW_SLIDE_SHOW:
506 slideshow_enabled = !slideshow_enabled;
507 running_slideshow = slideshow_enabled;
508 break;
509 #endif
511 #ifdef IMGVIEW_NEXT_REPEAT
512 case IMGVIEW_NEXT_REPEAT:
513 #endif
514 case IMGVIEW_NEXT:
515 if (entries > 1)
516 return change_filename(DIR_NEXT);
517 break;
519 #ifdef IMGVIEW_PREVIOUS_REPEAT
520 case IMGVIEW_PREVIOUS_REPEAT:
521 #endif
522 case IMGVIEW_PREVIOUS:
523 if (entries > 1)
524 return change_filename(DIR_PREV);
525 break;
527 case IMGVIEW_ZOOM_IN:
528 #ifdef IMGVIEW_ZOOM_PRE
529 if (lastbutton != IMGVIEW_ZOOM_PRE)
530 break;
531 #endif
532 return ZOOM_IN;
533 break;
535 case IMGVIEW_ZOOM_OUT:
536 #ifdef IMGVIEW_ZOOM_PRE
537 if (lastbutton != IMGVIEW_ZOOM_PRE)
538 break;
539 #endif
540 return ZOOM_OUT;
541 break;
542 #ifdef IMGVIEW_RC_MENU
543 case IMGVIEW_RC_MENU:
544 #endif
545 case IMGVIEW_MENU:
546 #ifdef USEGSLIB
547 grey_show(false); /* switch off greyscale overlay */
548 #endif
549 if (show_menu() == 1)
550 return PLUGIN_OK;
552 #ifdef USEGSLIB
553 grey_show(true); /* switch on greyscale overlay */
554 #else
555 draw_image_rect(info, 0, 0,
556 info->width-info->x, info->height-info->y);
557 MYLCD_UPDATE();
558 #endif
559 break;
560 default:
561 if (rb->default_event_handler_ex(button, cleanup, NULL)
562 == SYS_USB_CONNECTED)
563 return PLUGIN_USB_CONNECTED;
564 break;
566 } /* switch */
568 if (button != BUTTON_NONE)
569 lastbutton = button;
570 } /* while (true) */
573 /********************* main function *************************/
575 /* callback updating a progress meter while image decoding */
576 void cb_progress(int current, int total)
578 rb->yield(); /* be nice to the other threads */
579 if(!running_slideshow)
581 rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN],
582 0, LCD_HEIGHT-8, LCD_WIDTH, 8,
583 total, 0, current, HORIZONTAL);
584 rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8);
586 #ifndef USEGSLIB
587 else
589 /* in slideshow mode, keep gui interference to a minimum */
590 rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN],
591 0, LCD_HEIGHT-4, LCD_WIDTH, 4,
592 total, 0, current, HORIZONTAL);
593 rb->lcd_update_rect(0, LCD_HEIGHT-4, LCD_WIDTH, 4);
595 #endif
598 /* how far can we zoom in without running out of memory */
599 static int min_downscale(int bufsize)
601 int downscale = 8;
603 if (img_mem(8) > bufsize)
604 return 0; /* error, too large, even 1:8 doesn't fit */
606 while (downscale > 1 && img_mem(downscale/2) <= bufsize)
607 downscale /= 2;
609 return downscale;
612 /* how far can we zoom out, to fit image into the LCD */
613 static int max_downscale(struct image_info *info)
615 int downscale = 1;
617 while (downscale < 8 && (info->x_size/downscale > LCD_WIDTH
618 || info->y_size/downscale > LCD_HEIGHT))
620 downscale *= 2;
623 return downscale;
626 /* set the view to the given center point, limit if necessary */
627 static void set_view(struct image_info *info, int cx, int cy)
629 int x, y;
631 /* plain center to available width/height */
632 x = cx - MIN(LCD_WIDTH, info->width) / 2;
633 y = cy - MIN(LCD_HEIGHT, info->height) / 2;
635 /* limit against upper image size */
636 x = MIN(info->width - LCD_WIDTH, x);
637 y = MIN(info->height - LCD_HEIGHT, y);
639 /* limit against negative side */
640 x = MAX(0, x);
641 y = MAX(0, y);
643 info->x = x; /* set the values */
644 info->y = y;
647 /* calculate the view center based on the bitmap position */
648 static void get_view(struct image_info *info, int *p_cx, int *p_cy)
650 *p_cx = info->x + MIN(LCD_WIDTH, info->width) / 2;
651 *p_cy = info->y + MIN(LCD_HEIGHT, info->height) / 2;
654 /* load, decode, display the image */
655 static int load_and_show(char* filename, struct image_info *info)
657 int status;
658 int cx, cy;
659 ssize_t remaining;
661 #if LCD_DEPTH > 1
662 rb->lcd_set_foreground(LCD_WHITE);
663 rb->lcd_set_background(LCD_BLACK);
664 rb->lcd_set_backdrop(NULL);
665 #endif
666 rb->lcd_clear_display();
668 rb->memset(info, 0, sizeof(*info));
669 remaining = buf_size;
671 if (rb->button_get(false) == IMGVIEW_MENU)
672 status = PLUGIN_ABORT;
673 else
674 status = load_image(filename, info, buf, &remaining);
676 if (status == PLUGIN_OUTOFMEM)
678 #if PLUGIN_BUFFER_SIZE >= MIN_MEM
679 if(plug_buf)
681 rb->lcd_setfont(FONT_SYSFIXED);
682 rb->lcd_clear_display();
683 rb->snprintf(print,sizeof(print),"%s:",rb->strrchr(filename,'/')+1);
684 rb->lcd_puts(0,0,print);
685 rb->lcd_puts(0,1,"Not enough plugin memory!");
686 rb->lcd_puts(0,2,"Zoom In: Stop playback.");
687 if(entries>1)
688 rb->lcd_puts(0,3,"Left/Right: Skip File.");
689 rb->lcd_puts(0,4,"Show Menu: Quit.");
690 rb->lcd_update();
691 rb->lcd_setfont(FONT_UI);
693 rb->button_clear_queue();
695 while (1)
697 int button = rb->button_get(true);
698 switch(button)
700 case IMGVIEW_ZOOM_IN:
701 plug_buf = false;
702 buf = rb->plugin_get_audio_buffer((size_t *)&buf_size);
703 /*try again this file, now using the audio buffer */
704 return PLUGIN_OTHER;
705 #ifdef IMGVIEW_RC_MENU
706 case IMGVIEW_RC_MENU:
707 #endif
708 case IMGVIEW_MENU:
709 return PLUGIN_OK;
711 case IMGVIEW_LEFT:
712 if(entries>1)
714 rb->lcd_clear_display();
715 return change_filename(DIR_PREV);
717 break;
719 case IMGVIEW_RIGHT:
720 if(entries>1)
722 rb->lcd_clear_display();
723 return change_filename(DIR_NEXT);
725 break;
726 default:
727 if(rb->default_event_handler_ex(button, cleanup, NULL)
728 == SYS_USB_CONNECTED)
729 return PLUGIN_USB_CONNECTED;
734 else
735 #endif
737 rb->splash(HZ, "Out of Memory");
738 file_pt[curfile] = NULL;
739 return change_filename(direction);
742 else if (status == PLUGIN_ERROR)
744 file_pt[curfile] = NULL;
745 return change_filename(direction);
747 else if (status == PLUGIN_ABORT) {
748 rb->splash(HZ, "aborted");
749 return PLUGIN_OK;
752 ds_max = max_downscale(info); /* check display constraint */
753 ds_min = min_downscale(remaining); /* check memory constraint */
754 if (ds_min == 0)
756 #if UNSCALED_IS_AVAILABLE
757 /* Can not resize the image but original one is available, so use it. */
758 ds_min = ds_max = 1;
759 #else
760 /* not enough memory to decode image. */
761 rb->splash(HZ, "too large");
762 file_pt[curfile] = NULL;
763 return change_filename(direction);
764 #endif
766 else if (ds_max < ds_min)
767 ds_max = ds_min;
769 ds = ds_max; /* initialize setting */
770 cx = info->x_size/ds/2; /* center the view */
771 cy = info->y_size/ds/2;
773 do /* loop the image prepare and decoding when zoomed */
775 status = get_image(info, ds); /* decode or fetch from cache */
776 if (status == PLUGIN_ERROR)
778 file_pt[curfile] = NULL;
779 return change_filename(direction);
782 set_view(info, cx, cy);
784 if(!running_slideshow)
786 rb->snprintf(print, sizeof(print), "showing %dx%d",
787 info->width, info->height);
788 rb->lcd_puts(0, 3, print);
789 rb->lcd_update();
792 MYLCD(clear_display)();
793 draw_image_rect(info, 0, 0,
794 info->width-info->x, info->height-info->y);
795 MYLCD_UPDATE();
797 #ifdef USEGSLIB
798 grey_show(true); /* switch on greyscale overlay */
799 #endif
801 /* drawing is now finished, play around with scrolling
802 * until you press OFF or connect USB
804 while (1)
806 status = scroll_bmp(info);
807 if (status == ZOOM_IN)
809 #if UNSCALED_IS_AVAILABLE
810 if (ds > 1)
811 #else
812 if (ds > ds_min)
813 #endif
815 #if UNSCALED_IS_AVAILABLE
816 /* if 1/1 is always available, jump ds from ds_min to 1. */
817 int zoom = (ds == ds_min)? ds_min: 2;
818 #else
819 const int zoom = 2;
820 #endif
821 ds /= zoom; /* reduce downscaling to zoom in */
822 get_view(info, &cx, &cy);
823 cx *= zoom; /* prepare the position in the new image */
824 cy *= zoom;
826 else
827 continue;
830 if (status == ZOOM_OUT)
832 if (ds < ds_max)
834 #if UNSCALED_IS_AVAILABLE
835 /* if ds is 1 and ds_min is > 1, jump ds to ds_min. */
836 int zoom = (ds < ds_min)? ds_min: 2;
837 #else
838 const int zoom = 2;
839 #endif
840 ds *= zoom; /* increase downscaling to zoom out */
841 get_view(info, &cx, &cy);
842 cx /= zoom; /* prepare the position in the new image */
843 cy /= zoom;
845 else
846 continue;
848 break;
851 #ifdef USEGSLIB
852 grey_show(false); /* switch off overlay */
853 #endif
854 rb->lcd_clear_display();
856 while (status != PLUGIN_OK && status != PLUGIN_USB_CONNECTED
857 && status != PLUGIN_OTHER);
858 #ifdef USEGSLIB
859 rb->lcd_update();
860 #endif
861 return status;
864 /******************** Plugin entry point *********************/
866 enum plugin_status plugin_start(const void* parameter)
868 int condition;
869 #ifdef USEGSLIB
870 long greysize; /* helper */
871 #endif
872 #if LCD_DEPTH > 1
873 old_backdrop = rb->lcd_get_backdrop();
874 #endif
876 if(!parameter) return PLUGIN_ERROR;
878 #if PLUGIN_BUFFER_SIZE >= MIN_MEM
879 buf = rb->plugin_get_buffer((size_t *)&buf_size);
880 #else
881 buf = rb->plugin_get_audio_buffer((size_t *)&buf_size);
882 #endif
884 rb->strcpy(np_file, parameter);
885 get_pic_list();
887 if(!entries) return PLUGIN_ERROR;
889 #if PLUGIN_BUFFER_SIZE >= MIN_MEM
890 if(!rb->audio_status())
892 plug_buf = false;
893 buf = rb->plugin_get_audio_buffer((size_t *)&buf_size);
895 #endif
897 #ifdef USEGSLIB
898 if (!grey_init(buf, buf_size, GREY_ON_COP,
899 LCD_WIDTH, LCD_HEIGHT, &greysize))
901 rb->splash(HZ, "grey buf error");
902 return PLUGIN_ERROR;
904 buf += greysize;
905 buf_size -= greysize;
906 #endif
908 /* should be ok to just load settings since the plugin itself has
909 just been loaded from disk and the drive should be spinning */
910 configfile_load(IMGVIEW_CONFIGFILE, config,
911 ARRAYLEN(config), IMGVIEW_SETTINGS_MINVERSION);
912 rb->memcpy(&old_settings, &settings, sizeof (settings));
914 /* Turn off backlight timeout */
915 backlight_force_on(); /* backlight control in lib/helper.c */
919 condition = load_and_show(np_file, &image_info);
920 } while (condition != PLUGIN_OK && condition != PLUGIN_USB_CONNECTED
921 && condition != PLUGIN_ERROR);
923 if (rb->memcmp(&settings, &old_settings, sizeof (settings)))
925 /* Just in case drive has to spin, keep it from looking locked */
926 rb->splash(0, "Saving Settings");
927 configfile_save(IMGVIEW_CONFIGFILE, config,
928 ARRAYLEN(config), IMGVIEW_SETTINGS_VERSION);
931 #ifdef DISK_SPINDOWN
932 /* set back ata spindown time in case we changed it */
933 rb->storage_spindown(rb->global_settings->disk_spindown);
934 #endif
936 /* Turn on backlight timeout (revert to settings) */
937 backlight_use_settings(); /* backlight control in lib/helper.c */
939 #ifdef USEGSLIB
940 grey_release(); /* deinitialize */
941 #endif
943 return condition;