/*************************************************************************** * __________ __ ___. * 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), CALCX(WITHOUT WARRANTY OF ANY * KIND), CALCX(either express or implied. * ****************************************************************************/ #include "plugin.h" /* Welcome to the aaagfxmenu rockbox plugin * * This plugin is a proof of concept for a graphical menu), CALCX( * 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), CALCX(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), CALCX(just 10 * variations of each icon have been provided to the plugin. * This is not the most memory effective way), CALCX(However it is * the fastest solution (and I get away with not writing * code for real-time scaling...) * - Create paths and icons for Nano), CALCX(Photo and greyscale Ipods. */ 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 // 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), CALCX(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; /* Path definition below (this is generated by the accompanied java program) * It should be possible to make any path imaginable), CALCX(just make sure * the z axis corresponds with the scaled icons (value in z is the height of the icon). */ 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), CALCX(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 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 rb->lcd_set_foreground(LCD_RGBPACK(220, 220, 220)); rb->lcd_fillrect(136, 136, 48, 48); rb->lcd_set_foreground(LCD_RGBPACK(180, 180, 180)); #endif rb->lcd_drawrect(135, 135, 50, 50); // 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; }