/*
Copyright (C) 1997-2001 Id Software, Inc.

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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

// menu_main.c -- the main menu
 
#include <ctype.h>
#ifdef _WIN32
#include <io.h>
#endif
#include "client.h"
#include "../client/qmenu.h"

static char *menu_in_sound		= "misc/menu1.wav";
static char *menu_move_sound	= "misc/menu2.wav";
static char *menu_out_sound		= "misc/menu3.wav";
static char *creditsBuffer;
static int	m_main_cursor;

#define NUM_CURSOR_FRAMES 15

qboolean	m_entersound;		// play after drawing a frame, so caching
								// won't disrupt the sound

cvar_t	*options_menu;
extern cvar_t	*alt_text_color;

void	(*m_drawfunc) (void);
const char *(*m_keyfunc) (int key);

//=============================================================================
/* Support Routines */

#define	MAX_MENU_DEPTH	8


typedef struct
{
	void	(*draw) (void);
	const char *(*key) (int k);
} menulayer_t;


menulayer_t	m_layers[MAX_MENU_DEPTH];
int		m_menudepth;

// Knghtmare- added Psychospaz's menu scaling stuff
float scaledVideo (float param)
{
	return param*menuScale.avg;
}

float videoScale (void)
{
	return menuScale.avg;
}
// end Knightmare

// From Q2max
void addPlayerButton (buttonmenuobject_t *thisObj, int index, float x, float y, float w, float h)
{
	thisObj->min[0] = x;
	thisObj->max[0] = x + w;
	thisObj->min[1] = y;
	thisObj->max[1] = y + h;
	thisObj->index = index;
}


void ActionStartMod (char *mod)
{
	//killserver, start mod, unbind keys, exec configs, and start demos
	Cbuf_AddText ("killserver\n");
	Cbuf_AddText (va("game %s\n", mod));
	Cbuf_AddText ("unbindall\n");
	Cbuf_AddText ("exec default.cfg\n");
	Cbuf_AddText ("exec kmq2config.cfg\n");
	Cbuf_AddText ("exec autoexec.cfg\n");
	Cbuf_AddText ("d1\n");
}


void M_Banner( char *name )
{
	//float ratio;
	int w, h;

	R_DrawGetPicSize (&w, &h, name );
	/*if (w)
	{
		ratio = 45.0/(float)h;
		h = 45;
		w *= ratio;
	}*/
	R_DrawStretchPic (
		viddef.width / 2 - scaledVideo(w)/2,
		viddef.height/ 2 - scaledVideo(150),
		scaledVideo(w), scaledVideo(h), name, 1.0);
	//R_DrawPic( viddef.width / 2 - w / 2, viddef.height / 2 - 110, name );
}

// Knightmare- added Psychospaz's mouse support
void refreshCursorButtons(void)
{
	cursor.buttonused[MOUSEBUTTON2] = true;
	cursor.buttonclicks[MOUSEBUTTON2] = 0;
	cursor.buttonused[MOUSEBUTTON1] = true;
	cursor.buttonclicks[MOUSEBUTTON1] = 0;
}

void M_PushMenu ( void (*draw) (void), const char *(*key) (int k) )
{
	int		i;

	if (Cvar_VariableValue ("maxclients") == 1 && Com_ServerState () && !cls.consoleActive) // Knightmare added
		Cvar_Set ("paused", "1");

	// Knightmare- if just opened menu, and ingame and not DM, grab screen first
	if (cls.key_dest != key_menu && !Cvar_VariableValue("deathmatch")
		&& Com_ServerState() == 2) //ss_game
		//&& !cl.cinematictime && Com_ServerState())
		R_GrabScreen();

	// if this menu is already present, drop back to that level
	// to avoid stacking menus by hotkeys
	for (i=0 ; i<m_menudepth ; i++)
		if (m_layers[i].draw == draw &&
			m_layers[i].key == key)
		{
			m_menudepth = i;
		}

	if (i == m_menudepth)
	{
		if (m_menudepth >= MAX_MENU_DEPTH)
			Com_Error (ERR_FATAL, "M_PushMenu: MAX_MENU_DEPTH");
		m_layers[m_menudepth].draw = m_drawfunc;
		m_layers[m_menudepth].key = m_keyfunc;
		m_menudepth++;
	}

	m_drawfunc = draw;
	m_keyfunc = key;

	m_entersound = true;

	// Knightmare- added Psychospaz's mouse support
	refreshCursorLink();
	refreshCursorButtons();

	cls.key_dest = key_menu;
}

void M_ForceMenuOff (void)
{
	// Knightmare- added Psychospaz's mouse support
	refreshCursorLink();
	m_drawfunc = 0;
	m_keyfunc = 0;
	cls.key_dest = key_game;
	m_menudepth = 0;
	Key_ClearStates ();
	if (!cls.consoleActive) // Knightmare added
		Cvar_Set ("paused", "0");
}

void M_PopMenu (void)
{
	S_StartLocalSound( menu_out_sound );
	if (m_menudepth < 1)
		Com_Error (ERR_FATAL, "M_PopMenu: depth < 1");
	m_menudepth--;

	m_drawfunc = m_layers[m_menudepth].draw;
	m_keyfunc = m_layers[m_menudepth].key;

	// Knightmare- added Psychospaz's mouse support
	refreshCursorLink();
	refreshCursorButtons();

	if (!m_menudepth)
		M_ForceMenuOff ();
}

void M_BackMenu (void *unused)
{
	M_PopMenu();
}

void Options_MenuDraw (void);
const char *Default_MenuKey( menuframework_s *m, int key )
{
	const char *sound = NULL;
	menucommon_s *item;

	if ( m )
	{
		if ( ( item = Menu_ItemAtCursor( m ) ) != 0 )
		{
			if ( item->type == MTYPE_FIELD )
			{
				if ( Field_Key( ( menufield_s * ) item, key ) )
					return NULL;
			}
		}
	}

	switch ( key )
	{
	case K_ESCAPE:
		if (m_drawfunc==Options_MenuDraw && options_menu->value>0)
		{
			refreshCursorLink();
			Cvar_SetValue( "options_menu", 0 );
		}
		else
			M_PopMenu();
		return menu_out_sound;
	case K_KP_UPARROW:
	case K_UPARROW:
		if ( m )
		{
			m->cursor--;
			// Knightmare- added Psychospaz's mouse support
			refreshCursorLink();

			Menu_AdjustCursor( m, -1 );
			sound = menu_move_sound;
		}
		break;
	case K_TAB:
	case K_KP_DOWNARROW:
	case K_DOWNARROW:
		if ( m )
		{
			m->cursor++;
			// Knightmare- added Psychospaz's mouse support

			refreshCursorLink();
			Menu_AdjustCursor( m, 1 );
			sound = menu_move_sound;
		}
		break;
	case K_KP_LEFTARROW:
	case K_LEFTARROW:
		if ( m )
		{
			Menu_SlideItem( m, -1 );
			sound = menu_move_sound;
		}
		break;
	case K_KP_RIGHTARROW:
	case K_RIGHTARROW:
		if ( m )
		{
			Menu_SlideItem( m, 1 );
			sound = menu_move_sound;
		}
		break;

	/*case K_MOUSE1:
	case K_MOUSE2:
	case K_MOUSE3:
	//Knightmare 12/22/2001
	case K_MOUSE4:
	case K_MOUSE5:*/
	//end Knightmare
	case K_JOY1:
	case K_JOY2:
	case K_JOY3:
	case K_JOY4:
	case K_AUX1:
	case K_AUX2:
	case K_AUX3:
	case K_AUX4:
	case K_AUX5:
	case K_AUX6:
	case K_AUX7:
	case K_AUX8:
	case K_AUX9:
	case K_AUX10:
	case K_AUX11:
	case K_AUX12:
	case K_AUX13:
	case K_AUX14:
	case K_AUX15:
	case K_AUX16:
	case K_AUX17:
	case K_AUX18:
	case K_AUX19:
	case K_AUX20:
	case K_AUX21:
	case K_AUX22:
	case K_AUX23:
	case K_AUX24:
	case K_AUX25:
	case K_AUX26:
	case K_AUX27:
	case K_AUX28:
	case K_AUX29:
	case K_AUX30:
	case K_AUX31:
	case K_AUX32:
		
	case K_KP_ENTER:
	case K_ENTER:
		if ( m )
			Menu_SelectItem( m );
		sound = menu_move_sound;
		break;
	}

	return sound;
}

//=============================================================================

/*
================
M_DrawCharacter

Draws one solid graphics character
cx and cy are in 320*240 coordinates, and will be centered on
higher res screens.
================
*/
void M_DrawCharacter (int cx, int cy, int num,
		int red, int green, int blue, int alpha, qboolean italic)
{
	if (videoScale() > 1)
		R_DrawScaledChar ( scaledVideo( cx + ((MENU_STATIC_WIDTH-320)/2) ),
							scaledVideo( cy + ((MENU_STATIC_HEIGHT- 240)/2) ),
							num, videoScale(), red, green, blue, alpha, italic);
	else
		R_DrawScaledChar ( cx + ((viddef.width - 320)>>1), cy + ((viddef.height - 240)>>1 ),
							num, videoScale(), red, green, blue, alpha, italic);
	//R_DrawChar ( cx + ((viddef.width - 320)>>1), cy + ((viddef.height - 240)>>1), num, 255);
}

void M_Print (int cx, int cy, char *str)
{
	int red=0, green=255, blue=0;
	TextColor ((int)alt_text_color->value, &red, &green, &blue);
	//DrawAltString (cx, cy, str, 255);
	while (*str)
	{
		M_DrawCharacter (cx, cy, (*str)+128, red,green,blue,255, false);
		str++;
		cx += MENU_FONT_SIZE;
	}
}

void M_PrintWhite (int cx, int cy, char *str)
{
	//DrawString (cx, cy, str, 255);
	while (*str)
	{
		M_DrawCharacter (cx, cy, *str, 255,255,255,255, false);
		str++;
		cx += MENU_FONT_SIZE;
	}
}

void M_DrawPic (int x, int y, char *pic)
{
	R_DrawPic (x + ((viddef.width - 320)>>1), y + ((viddef.height - 240)>>1), pic);
}


/*
=============
M_DrawCursor

Draws an animating cursor with the point at
x,y.  The pic will extend to the left of x,
and both above and below y.
=============
*/
void M_DrawCursor( int x, int y, int f )
{
	char	cursorname[80];
	static qboolean cached;
	int w,h;

	if ( !cached )
	{
		int i;

		for ( i = 0; i < NUM_CURSOR_FRAMES; i++ )
		{
			Com_sprintf( cursorname, sizeof( cursorname ), "m_cursor%d", i );

			R_DrawFindPic( cursorname );
		}
		cached = true;
	}

	Com_sprintf( cursorname, sizeof(cursorname), "m_cursor%d", f );
	R_DrawGetPicSize( &w, &h, cursorname );
	R_DrawStretchPic (	x,	y,	scaledVideo(w), scaledVideo(h), cursorname, 1.0);
	//R_DrawPic( x, y, cursorname );
}

void M_DrawTextBox (int x, int y, int width, int lines)
{
	int		cx, cy;
	int		n;

	// draw left side
	cx = x;
	cy = y;
	M_DrawCharacter (cx, cy, 1, 255,255,255,255, false);
	for (n = 0; n < lines; n++)
	{
		cy += MENU_FONT_SIZE;
		M_DrawCharacter (cx, cy, 4, 255,255,255,255, false);
	}
	M_DrawCharacter (cx, cy+MENU_FONT_SIZE, 7, 255,255,255,255, false);

	// draw middle
	cx += MENU_FONT_SIZE;
	while (width > 0)
	{
		cy = y;
		M_DrawCharacter (cx, cy, 2, 255,255,255,255, false);
		for (n = 0; n < lines; n++)
		{
			cy += MENU_FONT_SIZE;
			M_DrawCharacter (cx, cy, 5, 255,255,255,255, false);
		}
		M_DrawCharacter (cx, cy+MENU_FONT_SIZE, 8, 255,255,255,255, false);
		width -= 1;
		cx += MENU_FONT_SIZE;
	}

	// draw right side
	cy = y;
	M_DrawCharacter (cx, cy, 3, 255,255,255,255, false);
	for (n = 0; n < lines; n++)
	{
		cy += MENU_FONT_SIZE;
		M_DrawCharacter (cx, cy, 6, 255,255,255,255, false);
	}
	M_DrawCharacter (cx, cy+MENU_FONT_SIZE, 9, 255,255,255,255, false);
}

		
/*
=======================================================================

MAIN MENU

=======================================================================
*/
#define	MAIN_ITEMS	5

char *main_names[] =
{
	"m_main_game",
	"m_main_multiplayer",
	"m_main_options",
	"m_main_video",
	"m_main_quit",
	0
};

void findMenuCoords (int *xoffset, int *ystart, int *totalheight, int *widest)
{
	//float ratio;
	int w, h, i;

	*totalheight = 0;
	*widest = -1;

	for ( i = 0; main_names[i] != 0; i++ )
	{
		R_DrawGetPicSize( &w, &h, main_names[i] );

		/*if (w)
		{
			ratio = 32.0/(float)h;
			h = 32;
			w *= ratio;
		}*/

		if ( w > *widest )
			*widest = w;
		*totalheight += ( h + 12 );
	}

	*ystart = ( viddef.height / 2 - scaledVideo(110) );
	*xoffset = ( viddef.width - scaledVideo(*widest) + scaledVideo(70) ) / 2;
//	*xoffset = ( viddef.width  - scaledVideo(*widest) )/ 2 + scaledVideo(30);
}

void M_Main_Draw (void)
{
	int i;
	int w, h, last_h;
	int ystart;
	int	xoffset;
	int widest = -1;
	int totalheight = 0;
	char litname[80];

	findMenuCoords(&xoffset, &ystart, &totalheight, &widest);

	for ( i = 0; main_names[i] != 0; i++ )
	{
		if ( i != m_main_cursor )
		{
			R_DrawGetPicSize( &w, &h, main_names[i] );
			R_DrawStretchPic ( xoffset,
				ystart + scaledVideo(i * 40 + 13),
				scaledVideo(w), scaledVideo(h), main_names[i], 1.0);
			//R_DrawPic( xoffset, ystart + i * 40 + 13, main_names[i] );
		}
	}
	strcpy( litname, main_names[m_main_cursor] );
	strcat( litname, "_sel" );
	R_DrawGetPicSize( &w, &h, litname );
	R_DrawStretchPic (
		xoffset,
		ystart + scaledVideo(m_main_cursor * 40 + 13),
		scaledVideo(w+2), scaledVideo(h+2), litname, 1.0);
	//R_DrawPic( xoffset, ystart + m_main_cursor * 40 + 13, litname );

	M_DrawCursor(	xoffset - scaledVideo(25),
					ystart + scaledVideo(m_main_cursor * 40 + 11),
					(int)(cls.realtime / 100)%NUM_CURSOR_FRAMES );

	R_DrawGetPicSize( &w, &h, "m_main_plaque" );
	R_DrawStretchPic (
		xoffset - scaledVideo(w/2 + 50),
		ystart + scaledVideo(10),
		scaledVideo(w), scaledVideo(h), "m_main_plaque", 1.0);
	//R_DrawPic( xoffset - 30 - w, ystart, "m_main_plaque" );
	last_h = h;

	R_DrawGetPicSize( &w, &h, "m_main_logo" );
	R_DrawStretchPic (
		xoffset - scaledVideo(w/2 + 50),
		ystart + scaledVideo(last_h) + scaledVideo(30),
		scaledVideo(w), scaledVideo(h), "m_main_logo", 1.0);
	//R_DrawPic( xoffset - 30 - w, ystart + h + 5, "m_main_logo" );
}

typedef struct
{
	int	min[2];
	int max[2];

	void (*OpenMenu)(void);
} mainmenuobject_t;

void addButton (mainmenuobject_t *thisObj, int index, int x, int y)
{
	float ratio;
	//char *name;
	int w, h;

	R_DrawGetPicSize( &w, &h, main_names[index]);
	
	if (w)
	{
		ratio = 32.0/(float)h;
		h = 32;
		w *= ratio;
	}

	thisObj->min[0] = x; thisObj->max[0] = x + scaledVideo(w);
	thisObj->min[1] = y; thisObj->max[1] = y + scaledVideo(h);

	switch (index)
	{
	case 0:
		thisObj->OpenMenu = M_Menu_Game_f;
	case 1:
		thisObj->OpenMenu = M_Menu_Multiplayer_f;
	case 2:
		thisObj->OpenMenu = M_Menu_Options_f;
	case 3:
		thisObj->OpenMenu = M_Menu_Video_f;
	case 4:
		thisObj->OpenMenu = M_Menu_Quit_f;
	}
}

void openMenuFromMain (void)
{
	switch (m_main_cursor)
	{
		case 0:
			M_Menu_Game_f ();
			break;

		case 1:
			M_Menu_Multiplayer_f();
			break;

		case 2:
			M_Menu_Options_f ();
			break;

		case 3:
			M_Menu_Video_f ();
			break;

		case 4:
			M_Menu_Quit_f ();
			break;
	}
}

int MainMenuMouseHover;
void CheckMainMenuMouse (void)
{
	int ystart;
	int	xoffset;
	int widest;
	int totalheight;
	int i, oldhover;
	char *sound = NULL;
	mainmenuobject_t buttons[MAIN_ITEMS];

	oldhover = MainMenuMouseHover;
	MainMenuMouseHover = 0;

	findMenuCoords(&xoffset, &ystart, &totalheight, &widest);
	for ( i = 0; main_names[i] != 0; i++ )
		addButton (&buttons[i], i, xoffset, ystart + scaledVideo(i * 40 + 13));

	//Exit with double click 2nd mouse button
	if (!cursor.buttonused[MOUSEBUTTON2] && cursor.buttonclicks[MOUSEBUTTON2]==2)
	{
		M_PopMenu();
		sound = menu_out_sound;
		cursor.buttonused[MOUSEBUTTON2] = true;
		cursor.buttonclicks[MOUSEBUTTON2] = 0;
	}

	for (i=MAIN_ITEMS-1;i>=0;i--)
	{
		if (cursor.x>=buttons[i].min[0] && cursor.x<=buttons[i].max[0] &&
			cursor.y>=buttons[i].min[1] && cursor.y<=buttons[i].max[1])
		{
			if (cursor.mouseaction)
				m_main_cursor = i;

			MainMenuMouseHover = 1 + i;

			if (oldhover == MainMenuMouseHover && MainMenuMouseHover-1 == m_main_cursor &&
				!cursor.buttonused[MOUSEBUTTON1] && cursor.buttonclicks[MOUSEBUTTON1]==1)
			{
				openMenuFromMain();
				sound = menu_move_sound;
				cursor.buttonused[MOUSEBUTTON1] = true;
				cursor.buttonclicks[MOUSEBUTTON1] = 0;
			}
			break;
		}
	}

	if (!MainMenuMouseHover)
	{
		cursor.buttonused[MOUSEBUTTON1] = false;
		cursor.buttonclicks[MOUSEBUTTON1] = 0;
		cursor.buttontime[MOUSEBUTTON1] = 0;
	}

	cursor.mouseaction = false;

	if ( sound )
		S_StartLocalSound( sound );
}

const char *M_Main_Key (int key)
{
	const char *sound = menu_move_sound;

	switch (key)
	{
	case K_ESCAPE:
#ifdef ERASER_COMPAT_BUILD // special hack for Eraser build
		if (cls.state == ca_disconnected)
			M_Menu_Quit_f ();
		else
			M_PopMenu ();
#else	// Knightmare- can't exit menu if disconnected,
		// so restart demo loop
		if (cls.state == ca_disconnected)
			Cbuf_AddText ("d1\n");
		M_PopMenu ();
#endif
		break;

	case K_KP_DOWNARROW:
	case K_DOWNARROW:
		if (++m_main_cursor >= MAIN_ITEMS)
			m_main_cursor = 0;
		return sound;

	case K_KP_UPARROW:
	case K_UPARROW:
		if (--m_main_cursor < 0)
			m_main_cursor = MAIN_ITEMS - 1;
		return sound;

	case K_KP_ENTER:
	case K_ENTER:
		m_entersound = true;

		switch (m_main_cursor)
		{
		case 0:
			M_Menu_Game_f ();
			break;

		case 1:
			M_Menu_Multiplayer_f();
			break;

		case 2:
			M_Menu_Options_f ();
			break;

		case 3:
			M_Menu_Video_f ();
			break;

		case 4:
			M_Menu_Quit_f ();
			break;
		}
	}

	return NULL;
}


void M_Menu_Main_f (void)
{
	M_PushMenu (M_Main_Draw, M_Main_Key);
}


/*
=======================================================================

GALLERY MENU

=======================================================================
*/
#if 0
void M_Menu_Gallery_f( void )
{
	extern void Gallery_MenuDraw( void );
	extern const char *Gallery_MenuKey( int key );

	M_PushMenu( Gallery_MenuDraw, Gallery_MenuKey );
}
#endif


/*
=======================================================================

QUIT MENU

=======================================================================
*/

const char *M_Quit_Key (int key)
{
	switch (key)
	{
	case K_ESCAPE:
	case 'n':
	case 'N':
		M_PopMenu ();
		break;

	case 'Y':
	case 'y':
		cls.key_dest = key_console;
		CL_Quit_f ();
		break;

	default:
		break;
	}
	return NULL;
}


void M_Quit_Draw (void)
{
	int		w, h;

	R_DrawGetPicSize (&w, &h, "quit");
	R_DrawStretchPic (
		(viddef.width-scaledVideo(w))/2, 
		(viddef.height-scaledVideo(h))/2,
		scaledVideo(w), scaledVideo(h), "quit", 1.0);
	//R_DrawPic ( (viddef.width-w)/2, (viddef.height-h)/2, "quit");
}


void M_Menu_Quit_f (void)
{
	M_PushMenu (M_Quit_Draw, M_Quit_Key);
}



//=============================================================================
/* Menu Subsystem */


/*
=================
M_Init
=================
*/
void M_Init (void)
{
	// Knightmare- init this cvar here so M_Print can use it
	if (!alt_text_color)
		alt_text_color = Cvar_Get ("alt_text_color", "2", CVAR_ARCHIVE);
	
	Cmd_AddCommand ("menu_main", M_Menu_Main_f);
	Cmd_AddCommand ("menu_game", M_Menu_Game_f);
		Cmd_AddCommand ("menu_loadgame", M_Menu_LoadGame_f);
		Cmd_AddCommand ("menu_savegame", M_Menu_SaveGame_f);
		Cmd_AddCommand ("menu_joinserver", M_Menu_JoinServer_f);
			Cmd_AddCommand ("menu_addressbook", M_Menu_AddressBook_f);
		Cmd_AddCommand ("menu_startserver", M_Menu_StartServer_f);
			Cmd_AddCommand ("menu_dmoptions", M_Menu_DMOptions_f);
		Cmd_AddCommand ("menu_playerconfig", M_Menu_PlayerConfig_f);
			Cmd_AddCommand ("menu_downloadoptions", M_Menu_DownloadOptions_f);
		Cmd_AddCommand ("menu_credits", M_Menu_Credits_f );
	Cmd_AddCommand ("menu_multiplayer", M_Menu_Multiplayer_f );
	Cmd_AddCommand ("menu_video", M_Menu_Video_f);
		Cmd_AddCommand ("menu_video_advanced", M_Menu_Video_Advanced_f);
	Cmd_AddCommand ("menu_options", M_Menu_Options_f);
		Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
	Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
}


/*
=================================
Menu Mouse Cursor - psychospaz
=================================
*/

void refreshCursorMenu (void)
{
	cursor.menu = NULL;
}
void refreshCursorLink (void)
{
	cursor.menuitem = NULL;
}

int Slider_CursorPositionX ( menuslider_s *s )
{
	float range;

	range = ( s->curvalue - s->minvalue ) / ( float ) ( s->maxvalue - s->minvalue );

	if ( range < 0)
		range = 0;
	if ( range > 1)
		range = 1;

	return ( int )( scaledVideo(MENU_FONT_SIZE) + RCOLUMN_OFFSET + (SLIDER_RANGE)*scaledVideo(MENU_FONT_SIZE) * range );
}

int newSliderValueForX (int x, menuslider_s *s)
{
	float newValue;
	int newValueInt;
	int pos = x - scaledVideo(MENU_FONT_SIZE + RCOLUMN_OFFSET + s->generic.x) - s->generic.parent->x;

	newValue = ((float)pos)/((SLIDER_RANGE-1)*scaledVideo(MENU_FONT_SIZE));
	newValueInt = s->minvalue + newValue * (float)( s->maxvalue - s->minvalue );

	return newValueInt;
}

void Slider_CheckSlide( menuslider_s *s )
{
	if ( s->curvalue > s->maxvalue )
		s->curvalue = s->maxvalue;
	else if ( s->curvalue < s->minvalue )
		s->curvalue = s->minvalue;

	if ( s->generic.callback )
		s->generic.callback( s );
}

void Menu_DragSlideItem (menuframework_s *menu, void *menuitem)
{
//	menucommon_s *item = ( menucommon_s * ) menuitem;
	menuslider_s *slider = ( menuslider_s * ) menuitem;

	slider->curvalue = newSliderValueForX(cursor.x, slider);
	Slider_CheckSlide ( slider );
}

void Menu_ClickSlideItem (menuframework_s *menu, void *menuitem)
{
	int min, max;
	menucommon_s *item = ( menucommon_s * ) menuitem;
	menuslider_s *slider = ( menuslider_s * ) menuitem;

	min = menu->x + scaledVideo(item->x + Slider_CursorPositionX(slider) - 4);
	max = menu->x + scaledVideo(item->x + Slider_CursorPositionX(slider) + 4);

	if (cursor.x < min)
		Menu_SlideItem( menu, -1 );
	if (cursor.x > max)
		Menu_SlideItem( menu, 1 );
}

void CheckQuitMenuMouse(void)
{
	int maxs[2], mins[2];
	int w, h;

	R_DrawGetPicSize (&w, &h, "quit");

	mins[0] = (viddef.width-w)/2;
	maxs[0] = mins[0] + w; 
	mins[1] = (viddef.height-h)/2;
	maxs[1] = mins[1] + h; 

	if (cursor.x>=mins[0] && cursor.x<=maxs[0] &&
		cursor.y>=mins[1] && cursor.y<=maxs[1])
	{
		if (!cursor.buttonused[MOUSEBUTTON2] && cursor.buttonclicks[MOUSEBUTTON2]==2)
		{
			M_PopMenu ();
			cursor.buttonused[MOUSEBUTTON2] = true;
			cursor.buttonclicks[MOUSEBUTTON2] = 0;
		}
		if (!cursor.buttonused[MOUSEBUTTON1] && cursor.buttonclicks[MOUSEBUTTON1]==2)
		{
			CL_Quit_f ();
			cursor.buttonused[MOUSEBUTTON1] = true;
			cursor.buttonclicks[MOUSEBUTTON1] = 0;
		}
	}
}

void M_Think_MouseCursor (void)
{
	char * sound = NULL;
	menuframework_s *m = (menuframework_s *)cursor.menu;

	if (m_drawfunc == M_Main_Draw) //have to hack for main menu :p
	{
		CheckMainMenuMouse();
		return;
	}
	
	if (m_drawfunc == M_Quit_Draw)
	{
		CheckQuitMenuMouse();
		return;
	}
	
	if (m_drawfunc == M_Credits_MenuDraw) //have to hack for credits :p
	{
		if (cursor.buttonclicks[MOUSEBUTTON2])
		{
			cursor.buttonused[MOUSEBUTTON2] = true;
			cursor.buttonclicks[MOUSEBUTTON2] = 0;
			cursor.buttonused[MOUSEBUTTON1] = true;
			cursor.buttonclicks[MOUSEBUTTON1] = 0;
			S_StartLocalSound( menu_out_sound );
			if (creditsBuffer)
				FS_FreeFile (creditsBuffer);
			M_PopMenu();
			return;
		}
	}
	//mouse clicking on the player model menu...
	if (m_drawfunc == PlayerConfig_MenuDraw && menu_scale->value && viddef.width >= MENU_STATIC_WIDTH)
		PlayerConfig_MouseClick();
	if (m_drawfunc == Options_MenuDraw && options_menu->value==3)
		MenuCrosshair_MouseClick();

	if (!m)
		return;

	//Exit with double click 2nd mouse button

	if (cursor.menuitem)
	{
		//MOUSE1
		if (cursor.buttondown[MOUSEBUTTON1])
		{
			if (cursor.menuitemtype == MENUITEM_SLIDER)
			{
				Menu_DragSlideItem(m, cursor.menuitem);
			}
			else if (!cursor.buttonused[MOUSEBUTTON1] && cursor.buttonclicks[MOUSEBUTTON1])
			{
				if (cursor.menuitemtype == MENUITEM_ROTATE)
				{
					if (menu_rotate->value)					
						Menu_SlideItem( m, -1 );
					else			
						Menu_SlideItem( m, 1 );

					sound = menu_move_sound;
					cursor.buttonused[MOUSEBUTTON1] = true;
				}
				else
				{
					cursor.buttonused[MOUSEBUTTON1] = true;
					Menu_MouseSelectItem( cursor.menuitem );
					sound = menu_move_sound;
				}
			}
		}
		//MOUSE2
		if (cursor.buttondown[MOUSEBUTTON2] && cursor.buttonclicks[MOUSEBUTTON2])
		{
			if (cursor.menuitemtype == MENUITEM_SLIDER && !cursor.buttonused[MOUSEBUTTON2])
			{
				Menu_ClickSlideItem(m, cursor.menuitem);
				sound = menu_move_sound;
				cursor.buttonused[MOUSEBUTTON2] = true;
			}
			else if (!cursor.buttonused[MOUSEBUTTON2])
			{
				if (cursor.menuitemtype == MENUITEM_ROTATE)
				{
					if (menu_rotate->value)					
						Menu_SlideItem( m, 1 );
					else			
						Menu_SlideItem( m, -1 );

					sound = menu_move_sound;
					cursor.buttonused[MOUSEBUTTON2] = true;
				}
			}
		}
	}
	else if (!cursor.buttonused[MOUSEBUTTON2] && cursor.buttonclicks[MOUSEBUTTON2]==2 && cursor.buttondown[MOUSEBUTTON2])
	{
		if (m_drawfunc==PlayerConfig_MenuDraw)
			PConfigAccept();

		if (m_drawfunc==Options_MenuDraw && options_menu->value>0)
		{
			Cvar_SetValue( "options_menu", 0 );
			refreshCursorLink();
		}
		else
			M_PopMenu();

		sound = menu_out_sound;
		cursor.buttonused[MOUSEBUTTON2] = true;
		cursor.buttonclicks[MOUSEBUTTON2] = 0;
		cursor.buttonused[MOUSEBUTTON1] = true;
		cursor.buttonclicks[MOUSEBUTTON1] = 0;
	}

	if ( sound )
		S_StartLocalSound( sound );
}

void M_Draw_Cursor (void)
{
	float alpha = 1, scale = 1;
	int w,h;
	char *overlay = NULL;
	char *cur_img = NULL;

	if (m_drawfunc == M_Main_Draw)
	{
		if (MainMenuMouseHover)
		{
			if ((cursor.buttonused[0] && cursor.buttonclicks[0])
				|| (cursor.buttonused[1] && cursor.buttonclicks[1]))
			{
				cur_img = "/gfx/m_cur_click.pcx";
				alpha = 0.85 + 0.15*sin(anglemod(cl.time*0.005));
			}
			else
			{
				cur_img = "/gfx/m_cur_hover.pcx";
				alpha = 0.85 + 0.15*sin(anglemod(cl.time*0.005));
			}
		}
		else
			cur_img = "/gfx/m_cur_main.pcx";
		overlay = "/gfx/m_cur_over.pcx";
	}
	else
	{
		if (cursor.menuitem)
		{
			if (cursor.menuitemtype == MENUITEM_TEXT)
			{
				cur_img = "/gfx/m_cur_text.pcx";
			}
			else
			{
				if ((cursor.buttonused[0] && cursor.buttonclicks[0])
					|| (cursor.buttonused[1] && cursor.buttonclicks[1]))
				{
					cur_img = "/gfx/m_cur_click.pcx";
					alpha = 0.85 + 0.15*sin(anglemod(cl.time*0.005));
				}
				else
				{
					cur_img = "/gfx/m_cur_hover.pcx";
					alpha = 0.85 + 0.15*sin(anglemod(cl.time*0.005));
				}
				overlay = "/gfx/m_cur_over.pcx";
			}
		}
		else
		{
			cur_img = "/gfx/m_cur_main.pcx";
			overlay = "/gfx/m_cur_over.pcx";
		}
	}
	
	if (cur_img)
	{
		R_DrawGetPicSize( &w, &h, cur_img );
		R_DrawScaledPic( cursor.x - w/2, cursor.y - h/2,
			scaledVideo(scale), alpha, cur_img, true, false);

		if (overlay)
		{
			R_DrawGetPicSize( &w, &h, "/gfx/m_cur_over.pcx" );
			R_DrawScaledPic( cursor.x - w/2, cursor.y - h/2,
				scaledVideo(scale), 1, overlay, true, false);
		}
	}
}

/*void M_Draw_Cursor (void)
{
	int w,h;

	//get sizing vars
	R_DrawGetPicSize( &w, &h, "m_mouse_cursor" );
	w = scaledVideo(w)*0.5;
	h = scaledVideo(h)*0.5;
	R_DrawStretchPic (cursor.x-w/2, cursor.y-h/2, w, h, "m_mouse_cursor", 1.0);
}*/

void InitMenuScale (void)
{
	//this is for scaling the menu...
	//this is kinda overkill, but whatever...
	// Knightmare- allow disabling of menu scaling
	// also, don't scale if < 800x600, then it would be smaller
	if (menu_scale->value && viddef.width > MENU_STATIC_WIDTH )
	{
		menuScale.x = viddef.width/MENU_STATIC_WIDTH;
		menuScale.y = viddef.height/MENU_STATIC_HEIGHT;
		//menuScale.avg = (menuScale.x + menuScale.y)*0.5f;
		menuScale.avg = min(menuScale.x, menuScale.y); // use smaller value instead of average
	}
	else
	{
		menuScale.x = 1;
		menuScale.y = 1;
		menuScale.avg = 1;
	}
}

/*
=================
M_Draw
=================
*/
void M_Draw (void)
{
	if (cls.key_dest != key_menu)
		return;

	// Knigthmare- added Psychospaz's scaled menu stuff
	InitMenuScale();

	// repaint everything next frame
	SCR_DirtyScreen ();

	// dim everything behind it down
	if (cl.cinematictime > 0 || cls.state == ca_disconnected)
	{
		if (R_DrawFindPic("/gfx/menu_background.pcx")) {
			R_DrawStretchPic (0, 0, viddef.width, viddef.height, "/gfx/menu_background.pcx", 1.0);
			//R_DrawFadeScreen ();
		}
		else
			R_DrawFill (0,0,viddef.width, viddef.height, 0);
	}
	// ingame menu uses alpha
	else if (R_DrawFindPic("/gfx/menu_background.pcx"))
		R_DrawStretchPic (0, 0, viddef.width, viddef.height, "/gfx/menu_background.pcx", menu_alpha->value);
	else
		R_DrawFadeScreen ();

	// Knigthmare- added Psychospaz's mouse support
	refreshCursorMenu();

	m_drawfunc ();

	// delay playing the enter sound until after the
	// menu has been drawn, to avoid delay while
	// caching images
	if (m_entersound)
	{
		S_StartLocalSound( menu_in_sound );
		m_entersound = false;
	}

	// Knigthmare- added Psychospaz's mouse support
	//menu cursor for mouse usage :)
	M_Draw_Cursor();
}


/*
=================
M_Keydown
=================
*/
void M_Keydown (int key)
{
	const char *s;

	if (m_keyfunc)
		if ( ( s = m_keyfunc( key ) ) != 0 )
			S_StartLocalSound( ( char * ) s );
}


