/* $Id: menu.c,v 1.35 2004/01/04 19:45:56 stpohle Exp $ * Menuhandling */ #include "basic.h" #include "bomberclone.h" #include "menu.h" #include "menugui.h" #include "network.h" #include "ogcache-client.h" _menuitem menuitems[MENU_MAXENTRYS]; _menu menu; int menu_looprunning = 0; /* delete all informations and create a totally new menuscreen */ void menu_new (char *title, int x, int y) { int i; if (menu.oldscreen != NULL) menu_delete(); strncpy (menu.title, title, MENU_TITLELEN); menu.items = NULL; menu.focus = NULL; for (i = 0; i < MENU_MAXENTRYS; i++) { menuitems[i].id = -1; menuitems[i].type = -1; menuitems[i].next = NULL; } /* save the old background screen */ x = (1 + (int)(x / menu.images[1]->w)) * menu.images[1]->w; y = (1 + (int)(y / menu.images[3]->h)) * menu.images[3]->h; menu.oldscreenpos.x = ((gfx.res.x - (x + 2*menu.images[0]->w)) / 2); menu.oldscreenpos.y = ((gfx.res.y - (y + 2*menu.images[0]->h)) / 2); menu.oldscreenpos.w = x + 2*menu.images[0]->w; menu.oldscreenpos.h = y + 2*menu.images[0]->h; menu.oldscreen = gfx_copyscreen (&menu.oldscreenpos); menu.focus = NULL; menu_looprunning = 0; }; /* restore the screen and reset all needed informations, free the old screen */ void menu_delete () { gfx_restorescreen (menu.oldscreen, &menu.oldscreenpos); gfx_blitdraw (); SDL_FreeSurface (menu.oldscreen); menu.oldscreen = NULL; menuitems[0].next = NULL; menu.items = NULL; menu_looprunning = 0; if (GS_RUNNING) draw_field (); }; /* draw only a part of the Screen */ void menu_draw_background (SDL_Rect *updaterect) { int x,y, dx, dy; SDL_Rect dest, cdest, src, csrc, window; y = 0; // start at the updaterect. start pos for (; y <= (menu.oldscreenpos.h - 2*menu.images[0]->h - 1)/menu.images[4]->h; y++) { x = 0; // start at the updaterect. start pos for (; x <= (menu.oldscreenpos.w - 2*menu.images[0]->w - 1)/menu.images[4]->w; x++) { dest.x = x * menu.images[4]->w; // start pos dest.y = y * menu.images[4]->h; dx = (1+x) * menu.images[4]->w; // end pos if (dx >= (menu.oldscreenpos.w - 2*menu.images[0]->w)) dest.w = menu.images[4]->w - (dx - (menu.oldscreenpos.w - 2*menu.images[0]->w)); else dest.w = menu.images[4]->w; dy = (1+y) * menu.images[4]->h; if (dy >= (menu.oldscreenpos.h - 2*menu.images[0]->h)) dest.h = menu.images[4]->h - (dy - (menu.oldscreenpos.h - 2*menu.images[0]->h)); else dest.h = menu.images[4]->h; if (dest.w > 0 || dest.h > 0) { dest.x += MENUOFFSET_X; dest.y += MENUOFFSET_Y; src.x = 0; src.y = 0; src.h = dest.h; src.w = dest.w; if (updaterect == NULL) gfx_blit (menu.images[4], &src, gfx.screen, &dest, 10000); else { window = *updaterect; window.x += MENUOFFSET_X; window.y += MENUOFFSET_Y; rect_clipping (&src, &dest, &window, &csrc, &cdest); if (csrc.w < UINT16_HALF && csrc.h < UINT16_HALF && cdest.w < UINT16_HALF && cdest.h < UINT16_HALF) gfx_blit (menu.images[4], &csrc, gfx.screen, &cdest, 10000); } } } } }; /* draws the menuborders, this function does not save the background */ void menu_draw_border () { SDL_Rect dest; int i, dx; // draw top left dest.x = menu.oldscreenpos.x; dest.y = menu.oldscreenpos.y; dest.w = menu.images[0]->w; dest.h = menu.images[0]->h; gfx_blit (menu.images[0], NULL, gfx.screen, &dest, 10000); // draw top and below for (i = 0; i < ((menu.oldscreenpos.w - (2*menu.images[0]->w)) / menu.images[1]->w); i++) { dest.x = menu.oldscreenpos.x + menu.images[0]->w + (i * menu.images[1]->w); dest.y = menu.oldscreenpos.y; dest.w = menu.images[1]->w; dest.h = menu.images[1]->h; gfx_blit (menu.images[1], NULL, gfx.screen, &dest, 10000); dest.y = menu.oldscreenpos.y + menu.oldscreenpos.h - menu.images[7]->h; gfx_blit (menu.images[7], NULL, gfx.screen, &dest, 10000); } // draw top right dest.x = menu.oldscreenpos.x + menu.oldscreenpos.w - menu.images[2]->w; dest.y = menu.oldscreenpos.y; dest.w = menu.images[2]->w; dest.h = menu.images[2]->h; gfx_blit (menu.images[2], NULL, gfx.screen, &dest, 10000); // draw left and right for (i = 0; i < ((menu.oldscreenpos.h - (2*menu.images[0]->h)) / menu.images[3]->h); i++) { dest.x = menu.oldscreenpos.x; dest.y = menu.oldscreenpos.y + menu.images[0]->h + menu.images[3]->h * i; dest.w = menu.images[1]->w; dest.h = menu.images[1]->h; gfx_blit (menu.images[3], NULL, gfx.screen, &dest, 10000); dest.x = menu.oldscreenpos.x + menu.oldscreenpos.w - menu.images[5]->w; gfx_blit (menu.images[5], NULL, gfx.screen, &dest, 10000); } // draw below left dest.x = menu.oldscreenpos.x; dest.y = menu.oldscreenpos.y + menu.oldscreenpos.h - menu.images[7]->h; dest.w = menu.images[6]->w; dest.h = menu.images[6]->h; gfx_blit (menu.images[6], NULL, gfx.screen, &dest, 10000); // draw below right dest.x = menu.oldscreenpos.x + menu.oldscreenpos.w - menu.images[8]->w; dest.y = menu.oldscreenpos.y + menu.oldscreenpos.h - menu.images[8]->h; dest.w = menu.images[8]->w; dest.h = menu.images[8]->h; gfx_blit (menu.images[8], NULL, gfx.screen, &dest, 10000); menu_draw_background (NULL); // draw title dx = menu.oldscreenpos.x + (menu.oldscreenpos.w - font[2].size.x*strlen (menu.title)) / 2; font_gfxdrawbold (dx, menu.oldscreenpos.y + menu.images[0]->h + 8, menu.title, 2, COLOR_brown, 2, 10000); font_gfxdraw (dx, menu.oldscreenpos.y + menu.images[0]->h + 8, menu.title, 2, COLOR_yellow, 10000); }; /* draw the menu, even it is only put into the gfx_blitlist. gfx_blitdraw needs * to be called before the menu is drawed on the screen */ void menu_draw () { _menuitem *m; if (!menu_looprunning) return; menu_draw_border (); for (m = menu.items; m != NULL; m = m->next) menu_draw_menuitem (m); }; /* draw an item on the screen */ inline void menu_draw_menuitem (_menuitem *m) { if (!menu_looprunning) return; switch (m->type) { case (MENU_label): menu_draw_label (m); break; case (MENU_button): menu_draw_button (m); break; case (MENU_bool): menu_draw_bool (m); break; case (MENU_entrytext): case (MENU_entryint16): case (MENU_entryint32): case (MENU_entryfloat): menu_draw_entry (m); break; case (MENU_list): menu_draw_list (m); break; } }; /* reload all variables into all menuelements */ void menu_reload () { _menuitem *m; for (m = menu.items; m != NULL; m = m->next) menu_reload_menuitem (m); }; /* reload variable into menuelement */ inline void menu_reload_menuitem (_menuitem *m) { switch (m->type) { case (MENU_entrytext): case (MENU_entryint16): case (MENU_entryint32): case (MENU_entryfloat): menu_entry_restore (m); break; default: break; } }; /* find the last menuitem in the list. */ int menu_getlastitem (_menuitem *first) { int i = 0; _menuitem *result = first; if (first == NULL) // no first item there return -1; for (;result->next != NULL; result = result->next) i++; return i; } /* get the last and the first id number */ _menuitem *menu_get_firstid () { _menuitem *result = NULL, *mi = menu.items; for (mi = menu.items; mi != NULL; mi = mi->next) if ((result == NULL || mi->id < result->id) && mi->id != -1) result = mi; return result; }; _menuitem *menu_get_lastid () { _menuitem *result = NULL, *mi = menu.items; for (mi = menu.items; mi != NULL; mi = mi->next) if ((result == NULL || mi->id > result->id) && mi->id != -1) result = mi; return result; }; /* change the focus to the givin element */ void menu_change_focus (_menuitem *newfocus) { _menuitem *oldmi; if (newfocus == menu.focus) // no focus change return; /* lose focus */ if (menu.focus != NULL) { switch (menu.focus->type) { case (MENU_entryfloat): case (MENU_entryint16): case (MENU_entryint32): case (MENU_entrytext): menu_entry_lose_focus (menu.focus); break; } } /* draw the old and the new element */ oldmi = menu.focus; menu.focus = newfocus; if (oldmi != NULL) menu_draw_menuitem (oldmi); menu_draw_menuitem (menu.focus); /* get focus ... no function yet */ d_printf ("menu_change_focus: ID:%d Name:%s\n", menu.focus->id, menu.focus->label); }; /* focus next element, order by ID */ void menu_focus_next () { _menuitem *newmi = menu.focus, *mi, *oldmi = menu.focus; for (mi = menu.items; mi != NULL; mi = mi->next) if (mi->id != oldmi->id && mi->id > menu.focus->id && (mi->id < newmi->id || newmi == oldmi)) newmi = mi; if (newmi == oldmi) menu_change_focus (menu_get_firstid()); else menu_change_focus (newmi); }; /* focus previous element, order by ID */ void menu_focus_prev () { _menuitem *newmi = menu.focus, *mi, *oldmi = menu.focus; for (mi = menu.items; mi != NULL; mi = mi->next) if (mi->id != -1 && mi->id != oldmi->id && mi->id < oldmi->id && (mi->id > newmi->id || newmi == oldmi)) newmi = mi; if (newmi == oldmi) menu_change_focus (menu_get_lastid()); else menu_change_focus (newmi); }; /* focus element with id ID */ void menu_focus_id (int id) { _menuitem *mi, *oldmi = menu.focus; for (mi = menu.items; mi != NULL; mi = mi->next) if (mi->id == id) menu_change_focus (mi); menu_draw_menuitem (oldmi); if (menu.focus != oldmi) menu_draw_menuitem (menu.focus); }; /* menu loop, programm will stay in here as long as no ESCAPE is pressed * and as long as no Button is clicked. Return of -2 means something needs to reordered */ int menu_loop () { SDL_Event event; Uint8 *keys; int keypressed = 0, done = 0, eventstate = 0, reorder = 0; menu_looprunning = 1; /* check if the focus is set to something, if not * set the focus to the first item */ if (menu.focus == NULL) { menu.focus = menu.items; menu_focus_id (0); } if (menu.focus == NULL) { d_fatal ("menu_loop: focus == NULL, something went wrong\n"); menu_looprunning = 0; return -1; } keys = SDL_GetKeyState (NULL); if (keys[SDLK_RETURN] || keys[SDLK_ESCAPE]) keypressed = 1; timestamp = SDL_GetTicks (); // needed for time sync. menu_draw(); while (!reorder && !done && bman.state != GS_quit) { gfx_blitdraw (); /* do the network loop if we have to */ if (bman.sock > 0) { network_loop (); if (bman.notifygamemaster) reorder = ogc_loop (); } eventstate = SDL_PollEvent (&event); if (eventstate >= 1) { switch (event.type) { case (SDL_QUIT): bman.state = GS_quit; done = 1; return -1; break; case (SDL_KEYDOWN): /* focus next element */ if (event.key.keysym.sym == SDLK_TAB) { keys = SDL_GetKeyState (NULL); if (keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT]) menu_focus_prev (); else menu_focus_next (); break; } else if (event.key.keysym.sym == SDLK_ESCAPE) { done = 1; return -1; break; } default: /* push events to the menu items */ switch (menu.focus->type) { case (MENU_button): done = menu_event_button (menu.focus, &event); break; case (MENU_bool): done = menu_event_bool (menu.focus, &event); break; case (MENU_entrytext): case (MENU_entryfloat): case (MENU_entryint16): case (MENU_entryint32): done = menu_event_entry (menu.focus, &event); break; case (MENU_label): break; case (MENU_list): done = menu_event_list (menu.focus, &event); break; } } } menu.focusto -= timediff; if (menu.focusto <= 0.0f) { menu.focusto = MENU_FOCUSVIS_BLINKTO; menu.focusvis = !menu.focusvis; menu_draw_menuitem (menu.focus); } s_calctimesync (); } menu_looprunning = 0; if (reorder) return -2; return menu.focus->id; }; /* create a list with all directory entrys, * except we can't put everything in the list because the list is too smal. * Return: number of entrys, Pointers will be set*/ int menu_create_dirlist (char *path, signed char dirflags, _charlist *cl, int maxentry) { int cnt; _direntry *destart, *de; destart = s_getdir (path); destart = s_dirfilter (destart, dirflags); for (cnt = 0, de = destart; (de != NULL && cnt < maxentry); de = de->next) { strncpy (cl[cnt].text, de->name, 255); if (de->next != NULL) cl[cnt].next = &cl[cnt+1]; else cl[cnt].next = NULL; cnt++; } return cnt; }; /* displays a file selectionmenu and * returns the name of the file */ static char menu_dir_name[LEN_PATHFILENAME]; char * menu_dir_select (char *title, char *path, signed char dirflags) { _charlist flist[MAX_DIRENTRYS]; int flcnt, menuselect; _charlist *selfile = NULL; flcnt = menu_create_dirlist (path, dirflags, flist, MAX_DIRENTRYS); menu_new (title, 300, 300); menu_create_list ("Dir", -1, 50, 200, 200, flist, &selfile, 1); menu_create_button ("OK", -1, 270, 150, 0); menuselect = menu_loop (); menu_delete (); if (menuselect < 0) return NULL; strncpy (menu_dir_name, selfile->text, LEN_PATHFILENAME); return menu_dir_name; };