Files
commandergenius/project/jni/application/lbreakout2/client/menu.c

431 lines
15 KiB
C

/***************************************************************************
menu.c - description
-------------------
begin : Thu Sep 20 2001
copyright : (C) 2001 by Michael Speck
email : kulkanie@gmx.net
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "manager.h"
List *menus = 0; /* list of menus used to delete them later */
extern StkFont *mfont, *mhfont, *mcfont;
extern int gap_height; /* gap size between items */
extern Menu *cur_menu;
#ifdef AUDIO_ENABLED
extern StkSound *wav_menu_motion, *wav_menu_click;
#endif
/*
====================================================================
Create menu.
====================================================================
*/
Menu *menu_create( char *name, int layout, int x, int y, int w, int h, int border, int add_to_list )
{
Menu *menu = calloc( 1, sizeof( Menu ) );
/* name */
if ( name )
menu->name = strdup( name );
else
menu->name = strdup( "none" );
/* layout */
menu->layout = layout;
menu->x = x + border; menu->y = y + border;
menu->w = w - border * 2; menu->h = h - border * 2;
/* items are cleared normally */
menu->items = list_create( LIST_AUTO_DELETE, item_delete );
/* add menu to list menus */
if ( add_to_list )
list_add( menus, menu );
/* create caption */
if ( name ) {
menu_add( menu, item_create_separator( name ) );
((Item*)menu->items->head->next->item)->font = mcfont;
menu_add( menu, item_create_separator( "" ) );
}
/* default fonts */
menu->font = mfont;
menu->hfont = mhfont;
menu->cfont = mcfont;
/* return menu */
return menu;
}
/*
====================================================================
Delete menu and all submenus starting with root menu
====================================================================
*/
void menu_delete( void *pmenu )
{
Menu *menu = (Menu*)pmenu;
if ( !menu ) return;
list_delete( menu->items );
if ( menu->name ) free( menu->name );
free( menu );
}
/*
====================================================================
Add item to menu.
====================================================================
*/
void menu_add( Menu *menu, Item *item )
{
list_add( menu->items, item );
if ( item->type == ITEM_LINK && (Menu*)item->link != menu )
((Menu*)item->link)->parent = menu;
}
/*
====================================================================
Adjust position and size of all entries according to layout.
====================================================================
*/
void menu_adjust( Menu *menu )
{
int height, x, y;
Item *item;
if ( menu->layout == MENU_LAYOUT_CENTERED ) {
/* get full height of all items + gaps */
height = menu->items->count * menu->hfont->height +
( menu->items->count - 1 ) * gap_height;
/* get positions of items */
y = menu->y + ( menu->h - height ) / 2;
x = menu->x;
/* set position */
list_reset( menu->items );
while( ( item = list_next( menu->items ) ) ) {
item->x = x; item->y = y;
item->w = menu->w; item->h = menu->hfont->height;
y += gap_height + menu->hfont->height;
item_adjust( item ); /* adjust alignment */
}
return;
}
fprintf( stderr, "menu_adjust: layout %i not supported\n", menu->layout );
}
/*
====================================================================
Select menu: clear current item and set extern variable cur_menu
====================================================================
*/
void menu_select( Menu *menu )
{
if ( cur_menu ) menu_unselect_cur_item( cur_menu );
cur_menu = menu;
menu->cur_item = 0;
hint_set( 0 );
}
/*
====================================================================
Show/hide all items
====================================================================
*/
void menu_hide( Menu *menu )
{
Item *item;
list_reset( menu->items );
while ( ( item = list_next( menu->items ) ) )
item_hide( item );
}
void menu_show( Menu *menu )
{
Item *item;
list_reset( menu->items );
while ( ( item = list_next( menu->items ) ) )
item_show( item );
}
/*
====================================================================
modify items according to event (if any)
====================================================================
*/
int menu_handle_event( Menu *menu, SDL_Event *event )
{
int result = ACTION_NONE;
Item *item, *old_item;
int item_used;
int x, y, xoff, yoff;
void (*callback)(void);
/* if value::grab is set do only except keyup events */
if ( menu->cur_item && menu->cur_item->type == ITEM_KEY && menu->cur_item->value->grab ) {
if ( event && event->type == SDL_KEYDOWN )
value_set_key( menu->cur_item->value, event->key.keysym.sym );
return result;
}
/* if other event occured check */
if ( event )
switch ( event->type ) {
case SDL_KEYDOWN:
switch ( event->key.keysym.sym ) {
case SDLK_ESCAPE:
/* if ESCAPE is pressed go up to last menu or leave */
if ( strequal( "Back", ((Item*)menu->items->tail->prev->item)->name ) )
menu_select( ((Item*)menu->items->tail->prev->item)->link );
else
if ( strequal( "Quit", ((Item*)menu->items->tail->prev->item)->name ) )
result = ACTION_QUIT;
break;
case SDLK_RETURN:
if ( !menu->cur_item ) break;
item_used = 1;
/* callback */
callback = menu->cur_item->callback;
/* action */
switch ( menu->cur_item->type ) {
case ITEM_ACTION: result = menu->cur_item->item_id; break;
case ITEM_LINK: menu_select( menu->cur_item->link ); break;
case ITEM_KEY: value_grab( menu->cur_item->value ); break;
case ITEM_SWITCH:
case ITEM_SWITCH_X:
case ITEM_RANGE:
value_inc( menu->cur_item->value );
break;
default: item_used = 0; break;
}
if ( item_used ) {
#ifdef AUDIO_ENABLED
stk_sound_play( wav_menu_click );
#endif
if ( callback ) (callback)();
}
break;
case SDLK_RIGHT:
if ( !menu->cur_item ) break;
item_used = 1;
/* callback */
callback = menu->cur_item->callback;
/* action */
switch ( menu->cur_item->type ) {
case ITEM_SWITCH:
case ITEM_SWITCH_X:
case ITEM_RANGE:
value_inc( menu->cur_item->value );
break;
default: item_used = 0; break;
}
#ifdef AUDIO_ENABLED
if ( item_used ) {
stk_sound_play( wav_menu_click );
#endif
if ( callback ) (callback)();
}
break;
case SDLK_LEFT:
if ( !menu->cur_item ) break;
item_used = 1;
/* callback */
callback = menu->cur_item->callback;
/* action */
switch ( menu->cur_item->type ) {
case ITEM_SWITCH:
case ITEM_SWITCH_X:
case ITEM_RANGE:
value_dec( menu->cur_item->value );
break;
default: item_used = 0; break;
}
#ifdef AUDIO_ENABLED
if ( item_used ) {
stk_sound_play( wav_menu_click );
#endif
if ( callback ) (callback)();
}
break;
case SDLK_UP:
menu_up( menu );
hint_set( menu->cur_item->hint );
#ifdef AUDIO_ENABLED
stk_sound_play( wav_menu_click );
#endif
break;
case SDLK_DOWN:
menu_down( menu );
hint_set( menu->cur_item->hint );
#ifdef AUDIO_ENABLED
stk_sound_play( wav_menu_click );
#endif
break;
default:
/* if type is edit: edit! */
if ( menu->cur_item && menu->cur_item->type == ITEM_EDIT ) {
value_edit( menu->cur_item->value, event->key.keysym.sym, event->key.keysym.unicode );
#ifdef AUDIO_ENABLED
stk_sound_play( wav_menu_click );
#endif
break;
}
break;
}
break;
case SDL_MOUSEBUTTONUP:
if ( !menu->cur_item ) break;
item_used = 1;
callback = menu->cur_item->callback;
switch ( menu->cur_item->type ) {
case ITEM_ACTION: result = menu->cur_item->item_id; break;
case ITEM_LINK: menu_select( menu->cur_item->link ); break;
case ITEM_SWITCH:
case ITEM_SWITCH_X:
case ITEM_RANGE:
if ( event->button.button == STK_BUTTON_LEFT )
value_inc( menu->cur_item->value );
else
value_dec( menu->cur_item->value );
break;
case ITEM_KEY: value_grab( menu->cur_item->value ); break;
default: item_used = 0; break;
}
if ( item_used ) {
#ifdef AUDIO_ENABLED
stk_sound_play( wav_menu_click );
#endif
if ( callback ) (callback)();
}
break;
}
/* mouse motion is handled directly */
SDL_GetRelativeMouseState( &xoff, &yoff );
if ( xoff != 0 || yoff != 0 ) {
SDL_GetMouseState( &x, &y );
/* select item mouse pointer is on */
old_item = menu->cur_item;
menu_unselect_cur_item( menu );
list_reset( menu->items );
while( ( item = list_next( menu->items ) ) )
if ( item_focus( item, x, y ) ) {
menu_select_item( menu, item );
if ( old_item != menu->cur_item ) {
#ifdef AUDIO_ENABLED
stk_sound_play( wav_menu_motion );
#endif
}
break;
}
if ( menu->cur_item )
hint_set( menu->cur_item->hint );
else
hint_set( 0 );
}
return result;
}
/*
====================================================================
Update alpha of items
====================================================================
*/
void menu_update( Menu *menu, int ms )
{
Item *item;
/* update alpha of all items */
list_reset( menu->items );
while ( ( item = list_next( menu->items ) ) )
item_update_alpha( item, ms );
}
/*
====================================================================
Select/unselect item: update menu::cur_item und item::highlight
====================================================================
*/
void menu_unselect_cur_item( Menu *menu )
{
if ( menu->cur_item ) menu->cur_item->highlighted = 0;
menu->cur_item = 0;
}
void menu_select_item( Menu *menu, Item *item )
{
menu->cur_item = item;
menu->cur_item->highlighted = 1;
}
/*
====================================================================
Go one valid menu item up or down.
====================================================================
*/
void menu_up( Menu *menu )
{
ListEntry *entry;
Item *item;
int valid = 0;
/* no selection so far: select first item after caption */
if ( !menu->cur_item ) {
menu_select_item( menu, list_get( menu->items, 2 ) );
return;
}
/* get entry -- MUST exist so don't check */
entry = list_entry( menu->items, menu->cur_item );
/* get next entry */
do {
entry = entry->prev;
if ( entry == menu->items->head )
entry = menu->items->tail->prev;
item = (Item*)entry->item;
if ( item->type == ITEM_SEPARATOR ) continue;
valid = 1;
} while ( !valid );
/* set as current */
menu_unselect_cur_item( menu );
menu_select_item( menu, entry->item );
}
void menu_down( Menu *menu )
{
ListEntry *entry;
Item *item;
int valid = 0;
/* no selection so far: select first item after caption */
if ( !menu->cur_item ) {
menu_select_item( menu, list_get( menu->items, 2 ) );
return;
}
/* get entry -- MUST exist so don't check */
entry = list_entry( menu->items, menu->cur_item );
/* get next entry */
do {
entry = entry->next;
if ( entry == menu->items->tail )
entry = menu->items->head->next;
item = (Item*)entry->item;
if ( item->type == ITEM_SEPARATOR ) continue;
valid = 1;
} while ( !valid );
/* set as current */
menu_unselect_cur_item( menu );
menu_select_item( menu, entry->item );
}
/*
====================================================================
Set fonts of menu and items.
====================================================================
*/
void menu_set_fonts(
Menu *menu, StkFont *cfont, StkFont *font, StkFont *hfont )
{
Item *item;
menu->cfont = cfont; menu->font = font; menu->hfont = hfont;
list_reset( menu->items );
while ( ( item = list_next( menu->items ) ) ) {
item->font = font;
item->hfont = hfont;
}
}
/*
====================================================================
Set background of menu and items.
====================================================================
*/
void menu_set_bkgnd( Menu *menu, SDL_Surface *bkgnd )
{
Item *item;
list_reset( menu->items );
while ( ( item = list_next( menu->items ) ) )
item->bkgnd = bkgnd;
}