/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2002 Robert E. Hak * * 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 #include #include "hwcompat.h" #include "lcd.h" #include "font.h" #include "backlight.h" #include "menu.h" #include "button.h" #include "kernel.h" #include "debug.h" #include "usb.h" #include "panic.h" #include "settings.h" #include "status.h" #include "screens.h" #include "talk.h" #ifdef HAVE_LCD_BITMAP #include "icons.h" #include "widgets.h" #endif struct menu { int top; int cursor; struct menu_item* items; int itemcount; int (*callback)(int, int); #ifdef HAVE_LCD_BITMAP bool use_buttonbar; /* true if a buttonbar is defined */ char *buttonbar[3]; #endif }; #define MAX_MENUS 5 #ifdef HAVE_LCD_BITMAP /* pixel margins */ #define MARGIN_X (global_settings.scrollbar && \ menu_lines < menus[m].itemcount ? SCROLLBAR_WIDTH : 0) +\ CURSOR_WIDTH #define MARGIN_Y (global_settings.statusbar ? STATUSBAR_HEIGHT : 0) /* position the entry-list starts at */ #define LINE_X 0 #define LINE_Y (global_settings.statusbar ? 1 : 0) #define CURSOR_X (global_settings.scrollbar && \ menu_lines < menus[m].itemcount ? 1 : 0) #define CURSOR_Y 0 /* the cursor is not positioned in regard to the margins, so this is the amount of lines we add to the cursor Y position to position it on a line */ #define CURSOR_WIDTH (global_settings.invert_cursor ? 0 : 4) #define SCROLLBAR_X 0 #define SCROLLBAR_Y lcd_getymargin() #define SCROLLBAR_WIDTH 6 #else /* HAVE_LCD_BITMAP */ #define LINE_X 1 /* X position the entry-list starts at */ #define MENU_LINES 2 #define CURSOR_X 0 #define CURSOR_Y 0 /* not really used for players */ #endif /* HAVE_LCD_BITMAP */ #define CURSOR_CHAR 0x92 static struct menu menus[MAX_MENUS]; static bool inuse[MAX_MENUS] = { false }; /* count in letter positions, NOT pixels */ void put_cursorxy(int x, int y, bool on) { #ifdef HAVE_LCD_BITMAP int fh, fw; int xpos, ypos; /* check here instead of at every call (ugly, but cheap) */ if (global_settings.invert_cursor) return; lcd_getstringsize("A", &fw, &fh); xpos = x*6; ypos = y*fh + lcd_getymargin(); if ( fh > 8 ) ypos += (fh - 8) / 2; #endif /* place the cursor */ if(on) { #ifdef HAVE_LCD_BITMAP lcd_bitmap ( bitmap_icons_6x8[Cursor], xpos, ypos, 4, 8, true); #else lcd_putc(x, y, CURSOR_CHAR); #endif } else { #if defined(HAVE_LCD_BITMAP) /* I use xy here since it needs to disregard the margins */ lcd_clearrect (xpos, ypos, 4, 8); #else lcd_putc(x, y, ' '); #endif } } void menu_draw(int m) { int i = 0; #ifdef HAVE_LCD_BITMAP int fw, fh; int menu_lines; int height = LCD_HEIGHT; lcd_setfont(FONT_UI); lcd_getstringsize("A", &fw, &fh); if (global_settings.statusbar) height -= STATUSBAR_HEIGHT; if(global_settings.buttonbar && menus[m].use_buttonbar) { buttonbar_set(menus[m].buttonbar[0], menus[m].buttonbar[1], menus[m].buttonbar[2]); height -= BUTTONBAR_HEIGHT; } menu_lines = height / fh; #else int menu_lines = MENU_LINES; #endif lcd_clear_display(); #ifdef HAVE_LCD_BITMAP lcd_setmargins(MARGIN_X,MARGIN_Y); /* leave room for cursor and icon */ #endif /* Adjust cursor pos if it's below the screen */ if (menus[m].cursor - menus[m].top >= menu_lines) menus[m].top++; /* Adjust cursor pos if it's above the screen */ if(menus[m].cursor < menus[m].top) menus[m].top = menus[m].cursor; for (i = menus[m].top; (i < menus[m].itemcount) && (i menu_lines) scrollbar(SCROLLBAR_X, SCROLLBAR_Y, SCROLLBAR_WIDTH - 1, height, menus[m].itemcount, menus[m].top, menus[m].top + menu_lines, VERTICAL); if(global_settings.buttonbar && menus[m].use_buttonbar) buttonbar_draw(); #endif status_draw(true); lcd_update(); } /* * Move the cursor to a particular id, * target: where you want it to be */ static void put_cursor(int m, int target) { int voice_id; menus[m].cursor = target; menu_draw(m); /* "say" the entry under the cursor */ if(global_settings.talk_menu) { voice_id = menus[m].items[menus[m].cursor].voice_id; if (voice_id >= 0) /* valid ID given? */ talk_id(voice_id, false); /* say it */ } } int menu_init(struct menu_item* mitems, int count, int (*callback)(int, int), char *button1, char *button2, char *button3) { int i; for ( i=0; i position; i--) menus[menu].items[i] = menus[menu].items[i - 1]; /* Increase the count */ menus[menu].itemcount++; /* Update the current item */ menus[menu].items[position].desc = desc; menus[menu].items[position].voice_id = voice_id; menus[menu].items[position].function = function; } /* * Property function - return the "count" of menu items in "menu" */ int menu_count(int menu) { return menus[menu].itemcount; } /* * Allows a menu item at the current cursor position in "menu" to be moved up the list */ bool menu_moveup(int menu) { struct menu_item swap; /* can't be the first item ! */ if( menus[menu].cursor == 0) return false; /* use a temporary variable to do the swap */ swap = menus[menu].items[menus[menu].cursor - 1]; menus[menu].items[menus[menu].cursor - 1] = menus[menu].items[menus[menu].cursor]; menus[menu].items[menus[menu].cursor] = swap; menus[menu].cursor--; return true; } /* * Allows a menu item at the current cursor position in "menu" to be moved down the list */ bool menu_movedown(int menu) { struct menu_item swap; /* can't be the last item ! */ if( menus[menu].cursor == menus[menu].itemcount - 1) return false; /* use a temporary variable to do the swap */ swap = menus[menu].items[menus[menu].cursor + 1]; menus[menu].items[menus[menu].cursor + 1] = menus[menu].items[menus[menu].cursor]; menus[menu].items[menus[menu].cursor] = swap; menus[menu].cursor++; return true; }