menu_st *menu_handle_item(menu_st *menulist, int num) { item_st *item; /* out of bounds */ if(num < 0 || num >= menulist->num_items) { Dprintf("menu_handle_item::Invalid item"); return menulist; } item = &menulist->items[num]; menulist->lastsel = -1; if(SUB_MENU_HEADER & item->op) { /* Destroy timer */ menu_handle_timer(menulist, 1); /* create another sub-menu */ menulist = menu_right_transition(menulist, item); } else if(ACTION_MENU & item->op) { /* execute the function */ void (* fp)(void); fp = item->action; (* fp)(); menulist->lastsel = 0; } else if(BOOLEAN_MENU & item->op) { /* toggle boolean; draw */ item->sel_option = !(item->sel_option); if(item->setting != 0) ipod_set_setting(item->setting, item->sel_option); menu_retext_pixmap(menulist, num - menulist->top_item, item); } else if(OPTION_MENU & item->op) { /* rotate option; draw */ item->sel_option = ((item->sel_option + 1) > (item->item_count - 1) ? 0 : item->sel_option + 1); if(item->setting != 0) ipod_set_setting(item->setting, item->sel_option); menu_retext_pixmap(menulist, num - menulist->top_item, item); } else if(SETTING_ITEM & item->op) { if(item->setting != 0) ipod_set_setting(item->setting, item->item_count); menulist = menu_destroy(menulist); } /* this isnt an else, so you can do (ACTION_MENU|SUB_MENU_PREV) */ if(SUB_MENU_PREV & item->op) { menulist = menu_destroy(menulist); } return menulist; }
/* selects specified item */ void menu_select_item(menu_st *menulist, int sel) { int diff, i, j, tmp; /* if it goes off the end either way, do nothing */ if(sel > menulist->num_items - 1 || sel < 0) return; /* the difference in select */ diff = sel - menulist->top_item; /* set selected */ menulist->sel = sel; /* if sel is below the visible screen */ if(diff > (menulist->screen_items - 1)) { /* set top item */ menulist->top_item = sel - (menulist->screen_items - 1); /* for each time the screen shifts down, rotate the pixmaps */ for(j = diff - (menulist->screen_items - 1); j > 0; j--) { tmp = menulist->pixmap_pos[0]; for(i = 0; i < menulist->screen_items - 1; i++) menulist->pixmap_pos[i] = menulist->pixmap_pos[i + 1]; menulist->pixmap_pos[menulist->screen_items - 1] = tmp; /* draw appropriate text to the bottom pixmap */ menu_retext_pixmap(menulist, menulist->screen_items - 1, &menulist->items[sel - (j-1)]); } } /* if sel is above the visible screen */ else if(diff < 0) { /* set top item */ menulist->top_item = sel; /* for each time the screen shifts up, rotate the pixmaps */ for(j = diff; j < 0; j++) { tmp = menulist->pixmap_pos[menulist->screen_items - 1]; for(i = menulist->screen_items - 1; i > 0; i--) menulist->pixmap_pos[i] = menulist->pixmap_pos[i - 1]; menulist->pixmap_pos[0] = tmp; /* draw appropriate text to the top pixmap */ menu_retext_pixmap(menulist, 0, &menulist->items[sel - (j+1)]); } } }
/* does the drawing, safe(and recommended) to use {in, as} an exposure event */ void menu_draw(menu_st *menulist) { int i; /* appearance changed, force a redraw */ if(menulist->scheme_no != appearance_get_color_scheme() || get_current_font() != menulist->font) { menu_update_menu(menulist); } /* first draw; init onscreen text items */ if(menulist->init == 0) { for(i = (menulist->num_items > menulist->screen_items) ? menulist->screen_items : menulist->num_items; i; i--) menu_retext_pixmap(menulist, i - 1, &menulist->items[menulist->top_item + (i - 1)]); menulist->init = 1; } #if 0 else if(menulist->lastsel == menulist->sel) { Dprintf("Aborted draw because %d == %d\n", menulist->sel, menulist->lastsel); return; } Dprintf("Continuing, %d != %d\n", menulist->sel, menulist->lastsel); #endif /* draw each pixmap */ for(i = 0; i < menulist->screen_items; i++) menu_draw_item(menulist, i); /* erase the bottom unused part of the allocated screen */ GrSetGCForeground(menulist->menu_gc, appearance_get_color( CS_BG )); GrFillRect(menulist->menu_wid, menulist->menu_gc, menulist->x, menulist->height * menulist->screen_items, menulist->w, menulist->h - (menulist->height * menulist->screen_items)); GrSetGCForeground(menulist->menu_gc, BLACK); /* draw scrollbar if needed */ if(menulist->num_items > menulist->screen_items) { menulist->scrollbar = 1; menu_draw_scrollbar(menulist); } else menulist->scrollbar = 0; /* deal with the timer */ menu_handle_timer(menulist, 0); menulist->lastsel = menulist->sel; }
/* removes the referenced item from the menu */ void menu_delete_item(menu_st *menulist, int num) { int i, tmp; /* if num is off the end either way, do nothing */ if(num > menulist->num_items - 1 || num < 0) { Dprintf("menu_delete_item::Invalid item\n"); return; } if(menulist->alloc_items == 0) { Dprintf("menu_delete_item::Deleting from a static menu causes " "undefined behavior\n"); return; } /* assume removed item is onscreen */ tmp = menulist->pixmap_pos[num-menulist->top_item]; for(i = 0; i < (menulist->screen_items-(num-menulist->top_item))-1; i++) { menulist->pixmap_pos[(num-menulist->top_item) + i] = menulist->pixmap_pos[(num-menulist->top_item) + (i+1)]; menu_draw_item(menulist, num-menulist->top_item + i); } menulist->pixmap_pos[menulist->screen_items - 1] = tmp; /* actually remove the item */ for(i = num; i < menulist->num_items - 1; i++) menulist->items[i] = menulist->items[i + 1]; menulist->num_items--; /* if last item was selected, shift selected */ if(menulist->sel == menulist->num_items) menu_shift_selected(menulist, -1); /* erase pixmaps that are off the bottom of the list */ if(menulist->top_item + (menulist->screen_items - 1) > menulist->num_items - 1) menu_clear_pixmap(menulist, menulist->screen_items - 1); /* draw appropriate text to the bottom pixmap */ else menu_retext_pixmap(menulist, menulist->screen_items - 1, &menulist->items[menulist->top_item + (menulist->screen_items - 1)]); /* specify if scrollbar should draw */ if(menulist->num_items <= menulist->screen_items) menulist->scrollbar = 0; }
void menu_draw_timer(menu_st *menulist) { char *c = strdup(">"); int colors[] = {CS_ARROW0, CS_ARROW1, CS_ARROW2, CS_ARROW3, CS_ARROW3, CS_ARROW2, CS_ARROW1, CS_ARROW0}; if(menulist->items[menulist->sel].op & CFLASH) { menulist->items[menulist->sel].op ^= CFLASH; menu_clear_pixmap(menulist, menulist->sel - menulist->top_item); menu_retext_pixmap(menulist, menulist->sel - menulist->top_item, &menulist->items[menulist->sel]); menu_handle_timer(menulist, 0); free(c); return; } if(menulist->items[menulist->sel].text_width > menulist->w - (8 + (menulist->scrollbar ? 8 : 0))) { int item, diff, move; item = menulist->sel - menulist->top_item; diff = (menulist->items[menulist->sel].text_width + 8) - (menulist->w - (8 + (menulist->scrollbar ? 8 : 0))); menulist->timer_step++; move = (!((menulist->timer_step / diff) % 2) ? (menulist->timer_step % diff) : (diff - (menulist->timer_step % diff))); if (menulist->timer == INT_MAX - 1) menulist->timer = 0; /* xor the pixmap */ GrSetGCMode(menulist->menu_gc, GR_MODE_XOR); if (hw_version == 0 || hw_version == 0x6 || hw_version == 0xc || hw_version == 0xb) { /* make sure that the xor works properly for devices with * fbrev turned off (host, photo) */ GrSetGCForeground(menulist->menu_gc, WHITE); } GrFillRect(menulist->pixmaps[menulist->pixmap_pos[item]], menulist->menu_gc, move, 0, menulist->w, menulist->height); GrCopyArea(menulist->menu_wid, menulist->menu_gc, menulist->x, (item * menulist->height) + menulist->y, menulist->w - (menulist->scrollbar ? 8 : 0), menulist->height, menulist->pixmaps[menulist->pixmap_pos[item]], move, 0, 0); /* un umm xor the pixmap */ GrFillRect(menulist->pixmaps[menulist->pixmap_pos[item]], menulist->menu_gc, move, 0, menulist->w, menulist->height); GrSetGCMode(menulist->menu_gc, GR_MODE_SET); if (hw_version == 0 || hw_version == 0x6 || hw_version == 0xc || hw_version == 0xb) { /* reset fix for xor on certain devices (host, photo) */ GrSetGCForeground(menulist->menu_gc, BLACK); } free(c); return; } GrSetGCUseBackground(menulist->menu_gc, GR_FALSE); /* cycle through colors */ if (menulist->timer_step < 0 || menulist->timer_step >= 12) menulist->timer_step = 0; GrSetGCForeground(menulist->menu_gc, appearance_get_color(colors[menulist->timer_step < 8 ? menulist->timer_step : 7])); menulist->timer_step++; /* executable instead */ if(EXECUTE_MENU & menulist->items[menulist->sel].op) *c = 'x'; /* double; with a 1px offset for bold */ GrText(menulist->menu_wid, menulist->menu_gc, menulist->x + (menulist->w - 8) - 6, menulist->height * (menulist->sel - menulist->top_item) + menulist->y + 2, c, -1, GR_TFASCII | GR_TFTOP); GrText(menulist->menu_wid, menulist->menu_gc, menulist->x + (menulist->w - 8) - 7, menulist->height * (menulist->sel - menulist->top_item) + menulist->y + 2, c, -1, GR_TFASCII | GR_TFTOP); GrSetGCForeground(menulist->menu_gc, BLACK); GrSetGCUseBackground(menulist->menu_gc, GR_TRUE); free(c); }