https://bitbucket.org/hudson/magic-lantern
Revision 660b81c6efcb348b1f4e315a83f6ab54d1fc8679 authored by a1ex on 20 May 2011, 21:41:39 UTC, committed by a1ex on 20 May 2011, 21:41:39 UTC
1 parent 874fc66
Raw File
Tip revision: 660b81c6efcb348b1f4e315a83f6ab54d1fc8679 authored by a1ex on 20 May 2011, 21:41:39 UTC
Lens focus delay
Tip revision: 660b81c
menu.c
/** \file
 * Magic Lantern GUI
 */
/*
 * Copyright (C) 2009 Trammell Hudson <hudson+ml@osresearch.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.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 */

#include "dryos.h"
#include "version.h"
#include "bmp.h"
#include "gui.h"
#include "config.h"
#include "property.h"
#include "lens.h"
#include "font.h"
#include "menu.h"

static struct semaphore * menu_sem;
extern struct semaphore * gui_sem;
static int menu_damage;
static int menu_hidden;
static int menu_timeout;
static int show_only_selected; // for ISO, kelvin...
static int edit_mode = 0;

int get_menu_font_sel() 
{
	if (edit_mode) return FONT(FONT_LARGE,COLOR_WHITE,COLOR_RED);
	else return FONT(FONT_LARGE,COLOR_WHITE,13);
}

extern int gui_state;
void menu_show_only_selected()
{
	show_only_selected = 1;
	menu_damage = 1;
}

int draw_event = 0;
CONFIG_INT( "debug.menu-timeout", menu_timeout_time, 1000 ); // doesn't work and breaks rack focus

static void
draw_version( void )
{
	bmp_printf(
		FONT( FONT_SMALL, COLOR_WHITE, COLOR_BLUE ),
		0, 0,
		"Magic Lantern Firmware version %s (%s)\nBuilt on%s by %s\n%s",
		build_version,
		build_id,
		build_date,
		build_user,
		"http://magiclantern.wikia.com/"
	);

/*
	int y = 200;
	struct config * config = global_config;
	bmp_printf( FONT_SMALL, 0, y, "Config: %x", (unsigned) global_config );
	y += font_small.height;

	while( config )
	{
		bmp_printf( FONT_SMALL, 0, y, "'%s' => '%s'", config->name, config->value );
		config = config->next;
		y += font_small.height;
	}
*/
}


struct gui_task * gui_menu_task;
static struct menu * menus;


void
menu_binary_toggle(
	void *			priv
)
{
	unsigned * val = priv;
	*val = !*val;
}

void menu_ternary_toggle(void* priv)
{
	unsigned * val = priv;
	*val = mod(*val + 1, 3);
}

void menu_ternary_toggle_reverse( void* priv)
{
	unsigned * val = priv;
	*val = mod(*val - 1, 3);
}

void menu_quaternary_toggle(void* priv)
{
	unsigned * val = priv;
	*val = mod(*val + 1, 4);
}

void menu_quaternary_toggle_reverse( void* priv)
{
	unsigned * val = priv;
	*val = mod(*val - 1, 4);
}

void menu_quinternary_toggle(void* priv)
{
	unsigned * val = priv;
	*val = mod(*val + 1, 5);
}

void menu_quinternary_toggle_reverse( void* priv)
{
	unsigned * val = priv;
	*val = mod(*val - 1, 5);
}

void
menu_print(
	void *			priv,
	int			x,
	int			y,
	int			selected
)
{
	bmp_printf(
		selected ? MENU_FONT_SEL : MENU_FONT,
		x, y,
		"%s",
		(const char*) priv
	);
}


static struct menu *
menu_find_by_name(
	const char *		name
)
{
	take_semaphore( menu_sem, 0 );

	struct menu *		menu = menus;

	for( ; menu ; menu = menu->next )
	{
		if( streq( menu->name, name ) )
		{
			give_semaphore( menu_sem );
			return menu;
		}

		// Stop just before we get to the end
		if( !menu->next )
			break;
	}

	// Not found; create it
	struct menu * new_menu = AllocateMemory( sizeof(*new_menu) );
	if( !new_menu )
	{
		give_semaphore( menu_sem );
		return NULL;
	}

	new_menu->name		= name;
	new_menu->prev		= menu;
	new_menu->next		= NULL; // Inserting at end
	new_menu->children	= NULL;

	// menu points to the last entry or NULL if there are none
	if( menu )
	{
		// We are adding to the end
		menu->next		= new_menu;
		new_menu->selected	= 0;
	} else {
		// This is the first one
		menus			= new_menu;
		new_menu->selected	= 1;
	}

	give_semaphore( menu_sem );
	return new_menu;
}


void
menu_add(
	const char *		name,
	struct menu_entry *	new_entry,
	int			count
)
{
#if 1
	// Walk the menu list to find a menu
	struct menu *		menu = menu_find_by_name( name );
	if( !menu )
		return;

	take_semaphore( menu_sem, 0 );

	struct menu_entry *	head = menu->children;
	if( !head )
	{
		// First one -- insert it as the selected item
		head = menu->children	= new_entry;
		new_entry->next		= NULL;
		new_entry->prev		= NULL;
		new_entry->selected	= 1;
		new_entry++;
		count--;
	}

	// Find the end of the entries on the menu already
	while( head->next )
		head = head->next;

	while( count-- )
	{
		new_entry->selected	= 0;
		new_entry->next		= head->next;
		new_entry->prev		= head;
		head->next		= new_entry;

		head			= new_entry;
		new_entry++;
	}
	give_semaphore( menu_sem );
#else
	// Maybe later...
	struct menu_entry * child = head->child;
	if( !child )
	{
		// No other child entries; add this one
		// and select it
		new_entry->highlighted	= 1;
		new_entry->prev		= NULL;
		new_entry->next		= NULL;
		head->child		= new_entry;
		return;
	}

	// Walk the child list to find the end
	while( child->next )
		child = child->next;

	// Push the new entry onto the end of the list
	new_entry->selected	= 0;
	new_entry->prev		= child;
	new_entry->next		= NULL;
	child->next		= new_entry;
#endif
}


void
menu_display(
	struct menu_entry *	menu,
	int			x,
	int			y,
	int			selected
)
{
	while( menu )
	{
		if (!show_only_selected || menu->selected)
			menu->display(
				menu->priv,
				x,
				y,
				menu->selected
			);
		
		if (menu->selected && menu->help)
			bmp_printf(
				FONT(FONT_MED, COLOR_WHITE, COLOR_BLACK), 
				10 /* + ((700/font_med.width) - strlen(menu->help)) * font_med.width / 2*/, 450, 
				menu->help
			);

		y += font_large.height;
		menu = menu->next;
	}
}


void
menus_display(
	struct menu *		menu,
	int			orig_x,
	int			y
)
{
	int			x = orig_x;

	take_semaphore( menu_sem, 0 );

	for( ; menu ; menu = menu->next )
	{
		unsigned fontspec = FONT(
			FONT_MED,
			menu->selected ? COLOR_WHITE : COLOR_YELLOW,
			menu->selected ? 13 : COLOR_BLACK
		);
		if (!show_only_selected) bmp_printf( fontspec, x, y, "%6s", menu->name );
		x += fontspec_font( fontspec )->width * 6;

		if( menu->selected )
			menu_display(
				menu->children,
				orig_x + 20,
				y + fontspec_font( fontspec )->height + 4,
				1
			);
	}

	give_semaphore( menu_sem );
}


void
menu_entry_select(
	struct menu *	menu,
	int mode // 0 = normal, 1 = reverse, 2 = auto setting
)
{
	if( !menu )
		return;

	show_only_selected = 0;
	take_semaphore( menu_sem, 0 );
	struct menu_entry * entry = menu->children;

	for( ; entry ; entry = entry->next )
	{
		if( entry->selected )
			break;
	}
	give_semaphore( menu_sem );

	if( !entry )
		return;

	if(mode == 1)
	{
		if( entry->select_reverse ) entry->select_reverse( entry->priv );
		else if (entry->select) entry->select( entry->priv );
	}
	else if (mode == 2)
	{
		if( entry->select_auto ) entry->select_auto( entry->priv );
		else if (entry->select) entry->select( entry->priv );
	}
	else 
	{
		if( entry->select ) entry->select( entry->priv );
	}
}

/** Scroll side to side in the list of menus */
void
menu_move(
	struct menu *		menu,
	int			direction
)
{
	menu_damage = 1;

	if( !menu )
		return;

	show_only_selected = 0;
	int rc = take_semaphore( menu_sem, 100 );
	if( rc != 0 )
		return;

	// Deselect the current one
	menu->selected		= 0;

	if( direction < 0 )
	{
		if( menu->prev )
			menu = menu->prev;
		else {
			// Go to the last one
			while( menu->next )
				menu = menu->next;
		}
	} else {
		if( menu->next )
			menu = menu->next;
		else {
			// Go to the first one
			while( menu->prev )
				menu = menu->prev;
		}
	}

	// Select the new one (which might be the same)
	menu->selected		= 1;
	give_semaphore( menu_sem );
}


/** Scroll up or down in the currently displayed menu */
void
menu_entry_move(
	struct menu *		menu,
	int			direction
)
{
	if( !menu )
		return;

	show_only_selected = 0;
	int rc = take_semaphore( menu_sem, 100 );
	if( rc != 0 )
		return;

	struct menu_entry *	entry = menu->children;

	for( ; entry ; entry = entry->next )
	{
		if( entry->selected )
			break;
	}

	// Nothing selected?
	if( !entry )
	{
		give_semaphore( menu_sem );
		return;
	}

	// Deslect the current one
	entry->selected = 0;

	if( direction < 0 )
	{
		// First and moving up?
		if( entry->prev )
			entry = entry->prev;
		else {
			// Go to the last one
			while( entry->next )
				entry = entry->next;
		}
	} else {
		// Last and moving down?
		if( entry->next )
			entry = entry->next;
		else {
			// Go to the first one
			while( entry->prev )
				entry = entry->prev;
		}
	}

	// Select the new one, which might be the same as the old one
	entry->selected = 1;
	give_semaphore( menu_sem );
}

void menu_select_current(int reverse)
{
	struct menu * menu = menus;
	for( ; menu ; menu = menu->next )
		if( menu->selected )
			break;
	menu_entry_select(menu,reverse);
}

static void 
menu_redraw_if_damaged()
{
	if( menu_damage )
	{
		if (!lv_drawn()) show_only_selected = 0;
		//~ if (MENU_MODE || lv_drawn()) clrscr();
		bmp_fill( show_only_selected ? 0 : COLOR_BLACK, 0, 0, 720, 480 );
		menu_damage = 0;
		menus_display( menus, 10, 40 );
		update_stuff();
		update_disp_mode_bits_from_params();
	}
}

int menu_send_event(int event)
{
	ctrlman_dispatch_event(gui_menu_task, event, 0, 0);
}

static int
menu_handler(
	void *			priv,
	gui_event_t		event,
	int			arg2,
	int			arg3,
	unsigned		arg4
)
{
	static int k = 0;
	// Ignore periodic events (pass them on)
	if( 0
	||  event == GUI_TIMER2
	||  event == GUI_TIMER3
	||  event == GUI_TIMER4
	||  event == 0x1000007c
	||  event == 0x10000078
	)
		return 1; // 0 is too aggressive :)

/*	if( event != 0x10000098 && event != 0x100000db)
	{
		bmp_printf( FONT_SMALL, 400, 40,
			"evt %8x(%8x,%8x,%8x",
			event, arg2, arg3, arg4
		);
	}*/

		// Mine!  No one else gets it
		//~ return 0;
	//~ }

	//~ if( event != 1 )
	//~ {
		DebugMsg( DM_MAGIC, 3, "%s: event %x", __func__, event );
		if( draw_event )
        {
			bmp_printf( FONT_SMALL, 20, 10 + ((k) % 8) * 10, "EVENT%2d: %x args %8x/%8x; %8x/%8x; %8x/%8x", k % 100, event, arg2, arg2 ? (*(int*)arg2) : 0, arg3, arg3 ? (*(int*)arg3) : 0, arg4, arg4 ? (*(int*)arg4) : 0);
			bmp_printf( FONT_SMALL, 20, 10 + ((k+1) % 8) * 10, "                                             ");
            k += 1;
            // not dangerous any more :)
			//~ if (event != PRESS_LEFT_BUTTON && event != PRESS_RIGHT_BUTTON && event != PRESS_UP_BUTTON && event != PRESS_DOWN_BUTTON && event != PRESS_SET_BUTTON) return 0;
        }
	//~ }

	// Find the selected menu (should be cached?)
	struct menu * menu = menus;
	for( ; menu ; menu = menu->next )
		if( menu->selected )
			break;
	switch( event )
	{
	case INITIALIZE_CONTROLLER:
		DebugMsg( DM_MAGIC, 3, "Menu task INITIALIZE_CONTROLLER" );
		return 0;

	case GOT_TOP_OF_CONTROL:
		DebugMsg( DM_MAGIC, 3, "Menu task GOT_TOP_OF_CONTROL" );
		menu_damage = 1;
		menu_redraw_if_damaged();
		menu_damage = 1;
		break;
	case LOST_TOP_OF_CONTROL:
		gui_stop_menu();

	case TERMINATE_WINSYS:
		// Must propagate to all gui elements
		DebugMsg( DM_MAGIC, 3, "%s: TERMINATE_WINSYS", __func__ );
		gui_stop_menu();
		return 1;

	case DELETE_DIALOG_REQUEST:
		// Must not propagate
		DebugMsg( DM_MAGIC, 3, "%s: DELETE_DIALOG", __func__ );
		gui_stop_menu();
		return 0;

	case PRESS_MENU_BUTTON:
	case EVENTID_METERING_START: // If they press the shutter halfway
	case 0x10000048:
	case 0x10000062:
		gui_stop_menu();
		return 1;
	
	case EVENTID_94:
		// Generated when buttons are pressed?  Forward it on
		return 1;
	
	case PRESS_ZOOM_IN_BUTTON:
		edit_mode = !edit_mode;
		menu_damage = 1;
		break;

	case PRESS_UP_BUTTON:
		edit_mode = 0;
	case ELECTRONIC_SUB_DIAL_LEFT:
		menu_damage = 1;
		if (edit_mode) { int i; for (i = 0; i < 5; i++) { menu_entry_select( menu, 1 ); msleep(10); }}
		else menu_entry_move( menu, -1 );
		break;

	case PRESS_DOWN_BUTTON:
		edit_mode = 0;
	case ELECTRONIC_SUB_DIAL_RIGHT:
		menu_damage = 1;
		if (edit_mode) { int i; for (i = 0; i < 5; i++) { menu_entry_select( menu, 0 ); msleep(10); }}
		else menu_entry_move( menu, 1 );
		break;

	case DIAL_RIGHT:
	case PRESS_RIGHT_BUTTON:
		menu_damage = 1;
		if (edit_mode) menu_entry_select( menu, 0 );
		else menu_move( menu, 1 );
		break;

	case DIAL_LEFT:
	case PRESS_LEFT_BUTTON:
		menu_damage = 1;
		if (edit_mode) menu_entry_select( menu, 1 );
		else menu_move( menu, -1 );
		break;

	case PRESS_SET_BUTTON:
		if (edit_mode) edit_mode = 0;
		else menu_entry_select( menu, 0 ); // normal select
		menu_damage = 1;
		break;

	case PRESS_INFO_BUTTON:
    case 0x10000000: // PLAY
		menu_entry_select( menu, 1 ); // reverse select
		menu_damage = 1;
		break;

	case PRESS_DIRECT_PRINT_BUTTON:
		menu_entry_select( menu, 2 ); // auto setting select
		menu_damage = 1;
		break;

#if 0
	case PRESS_ZOOM_IN_BUTTON:
		gui_hide_menu( 100 );
		lens_focus_start( 0 );
		break;


#if 0
	// This breaks playback if enabled; figure out why!
	case PRESS_ZOOM_OUT_BUTTON:
		gui_hide_menu( 100 );
		lens_focus_start( -1 );
		break;
#endif

	case UNPRESS_ZOOM_IN_BUTTON:
	//case UNPRESS_ZOOM_OUT_BUTTON:
		gui_hide_menu( 2 );
		lens_focus_stop();
		break;
#endif

	case 1:          // Synthetic redraw event
		break;

	//~ case 0x10000097: // canon code might have drawn over menu
	case 0x100000e8: // when you press Q on ISO
		menu_damage = 1;
		break;

	case 0x10000086:
		// Who knows?  Fall through

	default:
		DebugMsg( DM_MAGIC, 3, "%s: unknown event %08x? %08x %08x %x08",
			__func__,
			event,
			arg2,
			arg3,
			arg4
		);
		return 1;
	}

	// If we end up here, something has been changed.
	// Reset the timeout
	menu_timeout = menu_timeout_time;

	// If we are hidden or no longer exit, do not redraw
	if( menu_hidden || !gui_menu_task )
		return 0;

	menu_redraw_if_damaged();

	return 0;
}





void
menu_init( void )
{
	menus = NULL;
	gui_menu_task = NULL;
	menu_sem = create_named_semaphore( "menus", 1 );
	gui_sem = create_named_semaphore( "gui", 0 );

	menu_find_by_name( "Audio" );
	menu_find_by_name( "LiveV" );
	menu_find_by_name( "Movie" );
	menu_find_by_name( "Shoot" );
	menu_find_by_name( "Expo" );
	//~ menu_find_by_name( "Brack" );
	menu_find_by_name( "Focus" );
	//~ menu_find_by_name( "LUA" );
	//menu_find_by_name( "Games" );
	menu_find_by_name( "Tweak" );
	menu_find_by_name( "Debug" );
	menu_find_by_name( "Config" );
	menu_find_by_name( " (i)" );
	//~ menu_find_by_name( "Boot" );

/*
	bmp_printf( FONT_LARGE, 0, 40, "Yes, use this battery" );
	gui_control( ELECTRONIC_SUB_DIAL_RIGHT, 1, 0 );
	msleep( 2000 );
	gui_control( PRESS_SET_BUTTON, 1, 0 );
	msleep( 2000 );

	// Try to defeat the battery message
	//GUI_SetErrBattery( 1 );
	//msleep( 100 );
	//StopErrBatteryApp();

	msleep( 1000 );
*/
}


void
gui_stop_menu( void )
{
	menu_hidden = 0;
	menu_damage = 0;

	if( !gui_menu_task )
		return;

	gui_task_destroy( gui_menu_task );
	gui_menu_task = NULL;

	//workaround, otherwise screen does not refresh after closing menu
	/*if (!lv_drawn())
	{
		while (get_halfshutter_pressed()) msleep(100);
		fake_simple_button(BGMT_Q);
	}*/
	
	lens_focus_stop();
	show_only_selected = 0;
	//~ powersave_set_config_for_menu(); // revert to your preferred setting for powersave

	if (MENU_MODE && !get_halfshutter_pressed())
	{
		fake_simple_button(BGMT_MENU);
		msleep(200);
	}
	else
	{
		redraw();
	}
}


void
gui_hide_menu(
	int			redisplay_time
)
{
	menu_hidden = redisplay_time;
	menu_damage = 1;
	bmp_fill( 0, 0, 0, 720, 480 );
}


int
gui_menu_shown( void )
{
	return (int) gui_menu_task;
}

int get_draw_event() { return draw_event; }

void toggle_draw_event( void * priv )
{
	draw_event = !draw_event;
}

static void
about_print_0(
	void *			priv,
	int			x,
	int			y,
	int			selected
)
{
	if (!selected) return;
	bmp_printf(FONT_LARGE,
		x, y,
		"Magic Lantern for 60D"
	);
	bmp_printf(FONT_MED,
		x, y + font_large.height,
"http://magiclantern.wikia.com/60D");

	bmp_printf(FONT_MED,
		x, y + font_large.height + font_med.height * 1 + 5,
"First version by Trammell, developed by Alex");

	char msg[500];
	snprintf(msg, sizeof(msg), 
		"Magic Lantern v.%s (%s)\n \n"
		"Built on %s \nby %s\n",
		build_version,
		build_id,
		build_date,
		build_user);

	int X = x;
	int Y = y + font_large.height + font_med.height * 3 + 10; 
	bmp_puts_w(FONT_MED, &X, &Y, 37, msg); 

	bmp_printf(FONT_MED,
		x, y + font_large.height + font_med.height * 10 + 15,
	"(scroll down for full credits)");
}

static void
about_print(
	void *			priv,
	int			x,
	int			y,
	int			selected
)
{
	y -= font_large.height;
	if (!selected) return;
	bmp_printf(FONT_LARGE,
		x, y,
		"Magic Lantern for 60D"
	);
	bmp_printf(FONT_MED,
		x, y + font_large.height,
"http://magiclantern.wikia.com/60D");

	bmp_printf(FONT_MED,
		x, y + font_large.height + font_med.height * 1 + 5,
"First version by Trammell, developed by Alex");

	bmp_printf(FONT_MED,
		x, y + font_large.height + font_med.height * 2 + 10,
"Crypto tools by Arm.Indy, 60D port by SztupY");

	bmp_printf(FONT_MED,
		x, y + font_large.height + font_med.height * 3 + 15,
"Code review and insights by AJ");

	bmp_printf(FONT_MED,
		x, y + font_large.height + font_med.height * 4 + 20,
"Patches by piersg, nandoide, stefano, trho,\n"
"      deti, tapani, phil, xaos, sztupy");

	bmp_printf(FONT_MED,
		x, y + font_large.height + font_med.height * 6 + 25,
"Card tools by Pel, Zeno, lichtjaar");

	bmp_printf(FONT_MED,
		x, y + font_large.height + font_med.height * 7 + 30,
"Cropmarks by Robert, bwwd, turbinicarpus,\n"
"      CameraRick");

	bmp_printf(FONT_MED,
		x, y + font_large.height + font_med.height * 9 + 35,
"Tutorials by sawomedia, Renny, Jeremy, Daniel,\n"
"      Dod3032, MediaUnlocked, 3615geek,\n"
"      CineDigital.tv, jeveuxdoncjefilme\n");
}


/*static struct menu_entry draw_prop_menus[] = {
	{
		.priv		= "Toggle draw-event",
		.display	= menu_print,
		.select		= toggle_draw_event,
	},
};*/

static struct menu_entry about_menu[] = {
	{
		.display = about_print_0
	},
	{
		.display = about_print
	}
};

static void
menu_task( void )
{
	int x, y;
	DebugMsg( DM_MAGIC, 3, "%s: Starting up\n", __func__ );

	// Add the draw_prop menu
	//~ menu_add( "Debug", draw_prop_menus, COUNT(draw_prop_menus) );
	menu_add( " (i)", about_menu, COUNT(about_menu));
	
	msleep(3000);
	while(1)
	{
		int rc = take_semaphore( gui_sem, 500 );
		if( rc != 0 )
		{
			// We woke up after 1 second
			if( !gui_menu_task )
				continue;

			// Count down the menu timeout
			if( --menu_timeout == 0 )
			{
				gui_stop_menu();
				continue;
			}

			// Count down the menu_hidden timer
			if( menu_hidden )
			{
				if( --menu_hidden != 0 )
					continue;
				// Force an update on timer expiration
				ctrlman_dispatch_event(
					gui_menu_task,
					GOT_TOP_OF_CONTROL,
					0,
					0
				);
			} else {
				// Inject a synthetic timing event
				ctrlman_dispatch_event(
					gui_menu_task,
					1,
					0,
					0
				);
			}

			continue;
		}

		if( gui_menu_task )
		{
			gui_stop_menu();
			continue;
		}
		
		if (!lv_drawn() && !MENU_MODE)
		{
			fake_simple_button(BGMT_MENU);
			while (!MENU_MODE) msleep(50);
		}
		msleep(200);
		
		DebugMsg( DM_MAGIC, 3, "Creating menu task" );
		menu_damage = 1;
		menu_hidden = 0;
		edit_mode = 0;
		gui_menu_task = gui_task_create( menu_handler, 0 );

		//~ zebra_pause();
		//~ display_on(); // ensure the menu is visible even if display was off
		//~ bmp_on();
		show_only_selected = 0;
	}
}

TASK_CREATE( "menu_task", menu_task, 0, 0x1e, 0x1000 );

int is_menu_active(char* name)
{
	struct menu * menu = menus;
	for( ; menu ; menu = menu->next )
		if( menu->selected )
			break;
	return !strcmp(menu->name, name);
}

void select_menu(char* name, int entry_index)
{
	struct menu * menu = menus;
	for( ; menu ; menu = menu->next )
	{
		menu->selected = !strcmp(menu->name, name);
		if (menu->selected)
		{
			struct menu_entry *	entry = menu->children;
			
			int i;
			for(i = 0 ; entry ; entry = entry->next, i++ )
				entry->selected = (i == entry_index);
		}
	}
}
back to top