/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   ( <_> )  \___|    < | \_\ ( <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id: aaagfxmenu.c), CALCX(v 0.7 2006-04-12 23:00:00 maeck Exp $
 *
 * Copyright (C) 2006 Marcel van Eck  (rockbox.maeck@gmail.com)
 * iPod nano calibrations by Max Ried (maxried@gmail.com)
 *
 * All files in this archive are subject to the GNU General Public License.
 * See the file COPYING in the source tree root for full license agreement.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/
#include "plugin.h"

/* Welcome to the aaagfxmenu rockbox plugin 
 * 
 * This plugin is a proof of concept for a graphical menu, 
 * it does about nothing except for showing a number of 
 * icons in a nice 3d circle. Sliding around on the Ipod 
 * scrollwheel will move the icons around. If you stop 
 * scrolling the icons will refocus on the one icon closest
 * to the center. This is the icon you would 'select' if the 
 * select key is clicked. 
 * 
 * For the devices without a scrollwheel, the left and right
 * button lets you scroll through the menu. This is just not
 * as elegant as the scrollwheel (however it is very effective).
 * 
 * 'Menu' takes you back to the menu.
 * 
 * things to do:
 * - Do something when 'select' is clicked.
 * - Insert this code into the existing menu drawing code so 
 *   the graphical menu is shown for Ipod videos on the 
 *   playlist/plugins menu.
 * - Scaling of the icons is done outside of Rockbox, just 10
 *   variations of each icon have been provided to the plugin. 
 *   This is not the most memory effective way), However it is
 *   the fastest solution (and I get away with not writing 
 *   code for real-time scaling...)
 */ 

PLUGIN_HEADER

/* Key assignement */
#if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
    (CONFIG_KEYPAD == IPOD_3G_PAD)
#define GFXMENU_ACTION BUTTON_ACTION
#define GFXMENU_QUIT BUTTON_MENU
#define GFXMENU_RIGHT2 BUTTON_LEFT
#define GFXMENU_LEFT2 BUTTON_RIGHT
#define GFXMENU_RIGHT BUTTON_SCROLL_FWD
#define GFXMENU_LEFT BUTTON_SCROLL_BACK
#elif (CONFIG_KEYPAD == IAUDIO_X5_PAD)
#define GFXMENU_QUIT BUTTON_POWER
#define GFXMENU_RIGHT BUTTON_RIGHT
#define GFXMENU_LEFT BUTTON_LEFT
#define GFXMENU_RIGHT2 BUTTON_UP
#define GFXMENU_LEFT2 BUTTON_DOWN
#elif (CONFIG_KEYPAD == GIGABEAT_PAD)
#define GFXMENU_QUIT BUTTON_A
#define GFXMENU_RIGHT BUTTON_RIGHT
#define GFXMENU_LEFT BUTTON_LEFT
#define GFXMENU_RIGHT2 BUTTON_UP
#define GFXMENU_LEFT2 BUTTON_DOWN
#else
#define GFXMENU_QUIT BUTTON_NAVI
#define GFXMENU_RIGHT2 BUTTON_UP
#define GFXMENU_LEFT2 BUTTON_DOWN
#define GFXMENU_RIGHT BUTTON_RIGHT
#define GFXMENU_LEFT BUTTON_LEFT
#endif

/* external bitmaps */
extern const fb_data gfxmenu_menuitems48[];
extern const fb_data gfxmenu_menuitems47[];
extern const fb_data gfxmenu_menuitems46[];
extern const fb_data gfxmenu_menuitems45[];
extern const fb_data gfxmenu_menuitems44[];
extern const fb_data gfxmenu_menuitems43[];
extern const fb_data gfxmenu_menuitems42[];
extern const fb_data gfxmenu_menuitems41[];
extern const fb_data gfxmenu_menuitems40[];
extern const fb_data gfxmenu_menuitems39[];
extern const fb_data gfxmenu_menuitems38[];

#define CALCX(x) x * LCD_WIDTH
#define CALCY(y) y * LCD_HEIGHT

#define ICON_SIZE_MAX 48
#define ICON_SIZE_MIN 38

// GFXMENU_WAIT_FOR_FOCUS is the number of cycles to wait 
// before automatic focussing to the center.
#define GFXMENU_WAIT_FOR_FOCUS 10

// GFXMENU_STEP is the step size when using the scroll wheel
// 1 is very nice, but slow (needs a lot of scrolling). 
// 4 seems okay (3 revolutions on scrollwheel for one revolution on screen).
#define GFXMENU_STEP 4

static struct plugin_api* rb;

const int path_elements = 180;
const int focus_in_path = 90;

// GFXMENU_MAX_MENU_ELEMENTS is the maximum number of menuitems 
// to be allocated by the application. It seems that 16 is a very 
// crowded circle of icons, but only suitable on G5.
#if (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
#define GFXMENU_MAX_MENU_ELEMENTS 16
#else
#define GFXMENU_MAX_MENU_ELEMENTS 9
#endif

/* Path definition below. 
 * It should be possible to make any path imaginable, just make sure 
 * the z axis corresponds with the scaled icons (value in z is the height of the icon).
 */
const unsigned int x_table[] = {
	CALCX(0.5000000), CALCX(0.5113636), CALCX(0.5227273),
	CALCX(0.5397727), CALCX(0.5511364), CALCX(0.5625000),
	CALCX(0.5738636), CALCX(0.5909091), CALCX(0.6022727),
	CALCX(0.6136364), CALCX(0.6306818), CALCX(0.6363636),
	CALCX(0.6477273), CALCX(0.6647727), CALCX(0.6761364),
	CALCX(0.6875000), CALCX(0.6988636), CALCX(0.7102273),
	CALCX(0.7215909), CALCX(0.7272727), CALCX(0.7386364),
	CALCX(0.7500000), CALCX(0.7613636), CALCX(0.7670455),
	CALCX(0.7784091), CALCX(0.7840909), CALCX(0.7954545),
	CALCX(0.8011364), CALCX(0.8068182), CALCX(0.8181818),
	CALCX(0.8238636), CALCX(0.8295455), CALCX(0.8352273),
	CALCX(0.8409091), CALCX(0.8465909), CALCX(0.8522727),
	CALCX(0.8579545), CALCX(0.8579545), CALCX(0.8636364),
	CALCX(0.8636364), CALCX(0.8693182), CALCX(0.8693182),
	CALCX(0.8693182), CALCX(0.8693182), CALCX(0.8693182),
	CALCX(0.8750000), CALCX(0.8693182), CALCX(0.8693182),
	CALCX(0.8693182), CALCX(0.8693182), CALCX(0.8693182),
	CALCX(0.8636364), CALCX(0.8636364), CALCX(0.8579545),
	CALCX(0.8579545), CALCX(0.8522727), CALCX(0.8465909),
	CALCX(0.8409091), CALCX(0.8352273), CALCX(0.8295455),
	CALCX(0.8238636), CALCX(0.8181818), CALCX(0.8068182),
	CALCX(0.8011364), CALCX(0.7954545), CALCX(0.7840909),
	CALCX(0.7784091), CALCX(0.7670455), CALCX(0.7613636),
	CALCX(0.7500000), CALCX(0.7386364), CALCX(0.7272727),
	CALCX(0.7215909), CALCX(0.7102273), CALCX(0.6988636),
	CALCX(0.6875000), CALCX(0.6761364), CALCX(0.6647727),
	CALCX(0.6477273), CALCX(0.6363636), CALCX(0.6306818),
	CALCX(0.6136364), CALCX(0.6022727), CALCX(0.5909091),
	CALCX(0.5738636), CALCX(0.5625000), CALCX(0.5511364),
	CALCX(0.5397727), CALCX(0.5227273), CALCX(0.5113636),
	CALCX(0.5000000), CALCX(0.4886364), CALCX(0.4772727),
	CALCX(0.4602273), CALCX(0.4488636), CALCX(0.4375000),
	CALCX(0.4261364), CALCX(0.4090909), CALCX(0.3977273),
	CALCX(0.3863636), CALCX(0.3693182), CALCX(0.3636364),
	CALCX(0.3522727), CALCX(0.3352273), CALCX(0.3238636),
	CALCX(0.3181818), CALCX(0.3011364), CALCX(0.2897727),
	CALCX(0.2840909), CALCX(0.2727273), CALCX(0.2613636),
	CALCX(0.2500000), CALCX(0.2386364), CALCX(0.2329545),
	CALCX(0.2215909), CALCX(0.2159091), CALCX(0.2045455),
	CALCX(0.1988636), CALCX(0.1931818), CALCX(0.1818182),
	CALCX(0.1761364), CALCX(0.1704545), CALCX(0.1647727),
	CALCX(0.1590909), CALCX(0.1534091), CALCX(0.1477273),
	CALCX(0.1420455), CALCX(0.1420455), CALCX(0.1363636),
	CALCX(0.1363636), CALCX(0.1306818), CALCX(0.1306818),
	CALCX(0.1306818), CALCX(0.1306818), CALCX(0.1306818),
	CALCX(0.1250000), CALCX(0.1306818), CALCX(0.1306818),
	CALCX(0.1306818), CALCX(0.1306818), CALCX(0.1306818),
	CALCX(0.1363636), CALCX(0.1363636), CALCX(0.1420455),
	CALCX(0.1420455), CALCX(0.1477273), CALCX(0.1534091),
	CALCX(0.1590909), CALCX(0.1647727), CALCX(0.1704545),
	CALCX(0.1761364), CALCX(0.1818182), CALCX(0.1931818),
	CALCX(0.1988636), CALCX(0.2045455), CALCX(0.2159091),
	CALCX(0.2215909), CALCX(0.2329545), CALCX(0.2386364),
	CALCX(0.2500000), CALCX(0.2613636), CALCX(0.2727273),
	CALCX(0.2840909), CALCX(0.2897727), CALCX(0.3011364),
	CALCX(0.3125000), CALCX(0.3238636), CALCX(0.3352273),
	CALCX(0.3522727), CALCX(0.3636364), CALCX(0.3693182),
	CALCX(0.3863636), CALCX(0.3977273), CALCX(0.4090909),
	CALCX(0.4261364), CALCX(0.4375000), CALCX(0.4488636),
	CALCX(0.4602273), CALCX(0.4772727), CALCX(0.4886364), };

const unsigned int y_table[] = {
	CALCY(0.2500000), CALCY(0.2556818), CALCY(0.2556818), CALCY(0.2556818),
	CALCY(0.2556818), CALCY(0.2556818), CALCY(0.2556818), CALCY(0.2556818),
	CALCY(0.2556818), CALCY(0.2556818), CALCY(0.2613636), CALCY(0.2613636),
	CALCY(0.2613636), CALCY(0.2670455), CALCY(0.2670455), CALCY(0.2670455),
	CALCY(0.2727273), CALCY(0.2727273), CALCY(0.2727273), CALCY(0.2784091),
	CALCY(0.2840909), CALCY(0.2840909), CALCY(0.2897727), CALCY(0.2897727),
	CALCY(0.2954545), CALCY(0.2954545), CALCY(0.3011364), CALCY(0.3011364),
	CALCY(0.3068182), CALCY(0.3068182), CALCY(0.3181818), CALCY(0.3181818),
	CALCY(0.3238636), CALCY(0.3238636), CALCY(0.3295455), CALCY(0.3352273),
	CALCY(0.3352273), CALCY(0.3409091), CALCY(0.3465909), CALCY(0.3522727), 
	CALCY(0.3579545), CALCY(0.3579545), CALCY(0.3636364), CALCY(0.3693182),
	CALCY(0.3693182), CALCY(0.3750000), CALCY(0.3806818), CALCY(0.3806818),
	CALCY(0.3863636), CALCY(0.3920455), CALCY(0.3920455), CALCY(0.3977273),
	CALCY(0.4034091), CALCY(0.4090909), CALCY(0.4147727), CALCY(0.4147727),
	CALCY(0.4204545), CALCY(0.4261364), CALCY(0.4261364), CALCY(0.4318182),
	CALCY(0.4318182), CALCY(0.4431818), CALCY(0.4431818), CALCY(0.4488636),
	CALCY(0.4488636), CALCY(0.4545455), CALCY(0.4545455), CALCY(0.4602273),
	CALCY(0.4602273), CALCY(0.4659091), CALCY(0.4715909), CALCY(0.4715909),
	CALCY(0.4772727), CALCY(0.4772727), CALCY(0.4772727), CALCY(0.4829545),
	CALCY(0.4829545), CALCY(0.4829545), CALCY(0.4886364), CALCY(0.4886364),
	CALCY(0.4886364), CALCY(0.4943182), CALCY(0.4943182), CALCY(0.4943182),
	CALCY(0.4943182), CALCY(0.4943182), CALCY(0.4943182), CALCY(0.4943182),
	CALCY(0.4943182), CALCY(0.4943182), CALCY(0.5000000), CALCY(0.4943182),
	CALCY(0.4943182), CALCY(0.4943182), CALCY(0.4943182), CALCY(0.4943182),
	CALCY(0.4943182), CALCY(0.4943182), CALCY(0.4943182), CALCY(0.4943182),
	CALCY(0.4886364), CALCY(0.4886364), CALCY(0.4886364), CALCY(0.4829545),
	CALCY(0.4829545), CALCY(0.4829545), CALCY(0.4772727), CALCY(0.4772727),
	CALCY(0.4772727), CALCY(0.4715909), CALCY(0.4715909), CALCY(0.4659091),
	CALCY(0.4602273), CALCY(0.4602273), CALCY(0.4545455), CALCY(0.4545455),
	CALCY(0.4488636), CALCY(0.4488636), CALCY(0.4431818), CALCY(0.4431818),
	CALCY(0.4318182), CALCY(0.4318182), CALCY(0.4261364), CALCY(0.4261364),
	CALCY(0.4204545), CALCY(0.4147727), CALCY(0.4147727), CALCY(0.4090909),
	CALCY(0.4034091), CALCY(0.3977273), CALCY(0.3920455), CALCY(0.3920455),
	CALCY(0.3863636), CALCY(0.3806818), CALCY(0.3806818), CALCY(0.3750000),
	CALCY(0.3693182), CALCY(0.3693182), CALCY(0.3636364), CALCY(0.3579545),
	CALCY(0.3579545), CALCY(0.3522727), CALCY(0.3465909), CALCY(0.3409091),
	CALCY(0.3352273), CALCY(0.3352273), CALCY(0.3295455), CALCY(0.3238636),
	CALCY(0.3238636), CALCY(0.3181818), CALCY(0.3125000), CALCY(0.3068182), 
	CALCY(0.3068182), CALCY(0.3011364), CALCY(0.3011364), CALCY(0.2954545),
	CALCY(0.2954545), CALCY(0.2897727), CALCY(0.2897727), CALCY(0.2840909),
	CALCY(0.2840909), CALCY(0.2784091), CALCY(0.2727273), CALCY(0.2727273),
	CALCY(0.2727273), CALCY(0.2670455), CALCY(0.2670455), CALCY(0.2670455),
	CALCY(0.2613636), CALCY(0.2613636), CALCY(0.2613636), CALCY(0.2556818),
	CALCY(0.2556818), CALCY(0.2556818), CALCY(0.2556818), CALCY(0.2556818),
	CALCY(0.2556818), CALCY(0.2556818), CALCY(0.2556818), CALCY(0.2556818),};

	 
	 
/* no need to scale these */
const unsigned char z_table[] = {
     38, 38, 38, 38, 38, 38, 38, 38, 
     38, 38, 38, 38, 38, 38, 38, 38, 
     38, 38, 39, 39, 39, 39, 39, 39, 
     39, 39, 40, 40, 40, 40, 40, 40, 
     40, 41, 41, 41, 41, 41, 41, 42, 
     42, 42, 42, 42, 42, 43, 43, 43, 
     43, 43, 43, 44, 44, 44, 44, 44, 
     44, 45, 45, 45, 45, 45, 45, 45, 
     46, 46, 46, 46, 46, 46, 46, 46, 
     47, 47, 47, 47, 47, 47, 47, 47, 
     47, 47, 47, 47, 47, 47, 47, 47, 
     47, 47, 48, 47, 47, 47, 47, 47, 
     47, 47, 47, 47, 47, 47, 47, 47, 
     47, 47, 47, 47, 47, 46, 46, 46, 
     46, 46, 46, 46, 46, 45, 45, 45, 
     45, 45, 45, 45, 44, 44, 44, 44, 
     44, 44, 43, 43, 43, 43, 43, 43, 
     42, 42, 42, 42, 42, 42, 41, 41, 
     41, 41, 41, 41, 40, 40, 40, 40, 
     40, 40, 40, 39, 39, 39, 39, 39, 
     39, 39, 39, 38, 38, 38, 38, 38, 
     38, 38, 38, 38, 38, 38, 38, 38, 
     38, 38, 38, 38, };
/*** End of path definition ***/


int menuitem_elements = GFXMENU_MAX_MENU_ELEMENTS;
int menuitem_current_position = 0;
int menuitem_position[GFXMENU_MAX_MENU_ELEMENTS];

char *menuitem_title[] = {
	"One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", 
	"Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen"
};


void cleanup(void *parameter)
{
    (void)parameter;
    
    rb->backlight_set_timeout(rb->global_settings->backlight_timeout);
}


int plugin_main(void)
{
    int button, distance;
    int center, x_pos, y_pos, pos;
    int menumove = 1;
	int menu_element;
	int wait_for_focus = GFXMENU_WAIT_FOR_FOCUS;
	int y[GFXMENU_MAX_MENU_ELEMENTS];
	int o[GFXMENU_MAX_MENU_ELEMENTS];
	int a, b, c;
    
    // setup
    int menuitem_distance = path_elements / menuitem_elements;
    for (menu_element = 0; menu_element < menuitem_elements; menu_element++) {
		menuitem_position[menu_element] = menu_element * menuitem_distance;
    }
	distance = menuitem_distance / 2;
	int focus1 = focus_in_path - distance;
	int focus2 = focus_in_path + distance;

    
#ifdef HAVE_LCD_COLOR
    rb->lcd_set_background(LCD_RGBPACK(255, 255, 255));
#endif
    
    
    // display
    while (true)
    {
    	if (menumove != 0) {
			// update positions
			for (menu_element = 0; menu_element < menuitem_elements; menu_element++) {
				int pos = menuitem_position[menu_element] + menumove; 
				if ((pos >= (path_elements-1)) && (menumove > 0)) {
					pos = pos - (path_elements-1);
				}
				if ((pos <= 0) && (menumove < 0)) {
					pos = (path_elements-1) + pos;
				}
				menuitem_position[menu_element] = pos;
			}

			// Sort draw order: Icons further away (lower y position) 
			//                  should be drawn before the icons 
			//                  positioned closer by. Sorted list ends
			//					in o[].
			for (menu_element = 0; menu_element < menuitem_elements; menu_element++) {
				y[menu_element] = y_table[menuitem_position[menu_element]];
				o[menu_element] = menu_element;
			}
			for (a = menuitem_elements-1; a >= 0; a--) {
				for (b = a; b < menuitem_elements-1; b++) {
					if (y[b] > y[b+1]) {
						c = y[b+1];	y[b+1] = y[b]; y[b] = c; 
						c = o[b+1];	o[b+1] = o[b]; o[b] = c;																
					}
				}
			}
			
	        rb->lcd_clear_display();

			// Draw focus area
#ifdef HAVE_LCD_COLOR			
			lcd_set_foreground(LCD_RGBPACK(220, 220, 220));
			lcd_fillrect(x_table[focus_in_path] - (ICON_SIZE_MAX >> 1) - 1, 96, ICON_SIZE_MAX+2, ICON_SIZE_MAX+2);
			lcd_set_foreground(LCD_RGBPACK(180, 180, 180));
#endif
			lcd_drawrect(x_table[focus_in_path] - (ICON_SIZE_MAX >> 1) - 1, 95, ICON_SIZE_MAX+2, ICON_SIZE_MAX+2);


			// Draw menu elements
			for (menu_element = 0; menu_element < menuitem_elements; menu_element++) {
				pos = menuitem_position[o[menu_element]];
				center = z_table[pos] / 2;
				x_pos = x_table[pos] - center;
				y_pos = y_table[pos] - center;
				int me = o[menu_element] % 10;
				
				// Draw scaled rectangle
				//rb->lcd_drawrect(x_pos, y_pos, z_table[pos], z_table[pos]);
				
				// Draw bitmap by selecting the right scale (I know, this is taking up a lot of memory, but its fast, okay..!?)
				switch(z_table[pos])
				{
					case 38:
						rb->lcd_bitmap_transparent_part(gfxmenu_menuitems38, 0, z_table[pos]*me, z_table[pos], x_pos, y_pos, z_table[pos], z_table[pos]);		
						break;
					case 39:
						rb->lcd_bitmap_transparent_part(gfxmenu_menuitems39, 0, z_table[pos]*me, z_table[pos], x_pos, y_pos, z_table[pos], z_table[pos]);		
						break;
					case 40:
						rb->lcd_bitmap_transparent_part(gfxmenu_menuitems40, 0, z_table[pos]*me, z_table[pos], x_pos, y_pos, z_table[pos], z_table[pos]);		
						break;
					case 41:
						rb->lcd_bitmap_transparent_part(gfxmenu_menuitems41, 0, z_table[pos]*me, z_table[pos], x_pos, y_pos, z_table[pos], z_table[pos]);		
						break;
					case 42:
						rb->lcd_bitmap_transparent_part(gfxmenu_menuitems42, 0, z_table[pos]*me, z_table[pos], x_pos, y_pos, z_table[pos], z_table[pos]);		
						break;
					case 43:
						rb->lcd_bitmap_transparent_part(gfxmenu_menuitems43, 0, z_table[pos]*me, z_table[pos], x_pos, y_pos, z_table[pos], z_table[pos]);		
						break;
					case 44:
						rb->lcd_bitmap_transparent_part(gfxmenu_menuitems44, 0, z_table[pos]*me, z_table[pos], x_pos, y_pos, z_table[pos], z_table[pos]);		
						break;
					case 45:
						rb->lcd_bitmap_transparent_part(gfxmenu_menuitems45, 0, z_table[pos]*me, z_table[pos], x_pos, y_pos, z_table[pos], z_table[pos]);		
						break;
					case 46:
						rb->lcd_bitmap_transparent_part(gfxmenu_menuitems46, 0, z_table[pos]*me, z_table[pos], x_pos, y_pos, z_table[pos], z_table[pos]);		
						break;
					case 47:
						rb->lcd_bitmap_transparent_part(gfxmenu_menuitems47, 0, z_table[pos]*me, z_table[pos], x_pos, y_pos, z_table[pos], z_table[pos]);		
						break;
					case 48:
						rb->lcd_bitmap_transparent_part(gfxmenu_menuitems48, 0, z_table[pos]*me, z_table[pos], x_pos, y_pos, z_table[pos], z_table[pos]);		
						break;	
				}																																															
			}
	
			// draw title of menuitem in focus
#ifdef HAVE_LCD_COLOR			
		    rb->lcd_set_foreground(LCD_RGBPACK(255, 0, 0));		
#endif
			for (menu_element = 0; menu_element < menuitem_elements; menu_element++) {
				if ((focus1 <= menuitem_position[menu_element]) & (menuitem_position[menu_element] < focus2)) {
			    	rb->lcd_puts(0,0, menuitem_title[menu_element]);
				}
			}

	        rb->lcd_update();    
    	} else {
    		rb->sleep(1);
    	}
    	
        /* Handle the user events */
		menumove = 0;
        button = 0;		
        button = rb->button_get(false);        
        switch(button)
        {
            case (GFXMENU_QUIT):
                cleanup(NULL);
                return PLUGIN_OK;                
                break;
                
            case (GFXMENU_RIGHT):
            case (0x4000010):
            	menumove = GFXMENU_STEP;
            	wait_for_focus = GFXMENU_WAIT_FOR_FOCUS;
            	break; 
            	
            case (GFXMENU_RIGHT2):
	            menumove = menuitem_distance;
	            wait_for_focus = GFXMENU_WAIT_FOR_FOCUS;
            	break;

            case (GFXMENU_LEFT):
            case (0x4000020):
               	menumove = -GFXMENU_STEP;
               	wait_for_focus = GFXMENU_WAIT_FOR_FOCUS;
            	break;
            	
            case (GFXMENU_LEFT2):
	            menumove = -menuitem_distance;
	            wait_for_focus = GFXMENU_WAIT_FOR_FOCUS;
            	break;
            	
           	default:           	
       			// If no keys are pressed, figure out which item is closed and focus on it	 
		   		if (button == 0) {
					if (--wait_for_focus <= 0) {
						for (menu_element = 0; menu_element < menuitem_elements; menu_element++) {
							if ((focus1 <= menuitem_position[menu_element]) & (menuitem_position[menu_element] < focus2)) {
								distance = focus_in_path - menuitem_position[menu_element];
								if (distance < 0) {
									menumove = -1;
								}
								if (distance > 0) {
									menumove = 1;
								}					
								if (distance == 0) {
									menumove = 0;							
								}
							}
						}
					}
		   		}
		   		
           	    if (rb->default_event_handler_ex(button, cleanup, NULL) == SYS_USB_CONNECTED) {
            		return PLUGIN_USB_CONNECTED;
        		}
				break;
	    }           
    }
}

/*************************** Plugin entry point ****************************/

enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
{
    int ret;
#define DEFAULT_WAIT_TIME 3
    rb = api; 
    (void)parameter;
    if (rb->global_settings->backlight_timeout > 0)
        rb->backlight_set_timeout(1);

    ret = plugin_main();

    return ret;
}
