538 lines
16 KiB
C++
538 lines
16 KiB
C++
/*
|
|
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.
|
|
|
|
*/
|
|
|
|
#include "extdll.h"
|
|
#include "basemenu.h"
|
|
#include "utils.h"
|
|
#include "keydefs.h"
|
|
#include "menu_btnsbmp_table.h"
|
|
|
|
#define ART_BANNER "gfx/shell/head_controls"
|
|
|
|
#define ID_BACKGROUND 0
|
|
#define ID_BANNER 1
|
|
#define ID_DEFAULTS 2
|
|
#define ID_ADVANCED 3
|
|
#define ID_DONE 4
|
|
#define ID_CANCEL 5
|
|
#define ID_KEYLIST 6
|
|
#define ID_TABLEHINT 7
|
|
#define ID_MSGBOX 8
|
|
#define ID_MSGTEXT 9
|
|
|
|
#define MAX_KEYS 256
|
|
#define CMD_LENGTH 38
|
|
#define KEY1_LENGTH 20+CMD_LENGTH
|
|
#define KEY2_LENGTH 20+KEY1_LENGTH
|
|
|
|
typedef struct
|
|
{
|
|
char keysBind[MAX_KEYS][CMD_LENGTH];
|
|
char firstKey[MAX_KEYS][20];
|
|
char secondKey[MAX_KEYS][20];
|
|
char keysDescription[MAX_KEYS][256];
|
|
char *keysDescriptionPtr[MAX_KEYS];
|
|
|
|
menuFramework_s menu;
|
|
|
|
menuBitmap_s background;
|
|
menuBitmap_s banner;
|
|
menuPicButton_s defaults;
|
|
menuPicButton_s advanced;
|
|
menuPicButton_s done;
|
|
menuPicButton_s cancel;
|
|
|
|
// redefine key wait dialog
|
|
menuAction_s msgBox;
|
|
menuAction_s dlgMessage;
|
|
|
|
menuScrollList_s keysList;
|
|
menuAction_s hintMessage;
|
|
char hintText[MAX_HINT_TEXT];
|
|
|
|
int bind_grab; // waiting for key input
|
|
} uiControls_t;
|
|
|
|
static uiControls_t uiControls;
|
|
|
|
/*
|
|
=================
|
|
UI_Controls_GetKeyBindings
|
|
=================
|
|
*/
|
|
static void UI_Controls_GetKeyBindings( const char *command, int *twoKeys )
|
|
{
|
|
int i, count = 0;
|
|
const char *b;
|
|
|
|
twoKeys[0] = twoKeys[1] = -1;
|
|
|
|
for( i = 0; i < 256; i++ )
|
|
{
|
|
b = KEY_GetBinding( i );
|
|
if( !b ) continue;
|
|
|
|
if( !stricmp( command, b ))
|
|
{
|
|
twoKeys[count] = i;
|
|
count++;
|
|
|
|
if( count == 2 ) break;
|
|
}
|
|
}
|
|
|
|
// swap keys if needed
|
|
if( twoKeys[0] != -1 && twoKeys[1] != -1 )
|
|
{
|
|
int tempKey = twoKeys[1];
|
|
twoKeys[1] = twoKeys[0];
|
|
twoKeys[0] = tempKey;
|
|
}
|
|
}
|
|
|
|
void UI_UnbindCommand( const char *command )
|
|
{
|
|
int i, l;
|
|
const char *b;
|
|
|
|
l = strlen( command );
|
|
|
|
for( i = 0; i < 256; i++ )
|
|
{
|
|
b = KEY_GetBinding( i );
|
|
if( !b ) continue;
|
|
|
|
if( !strncmp( b, command, l ))
|
|
KEY_SetBinding( i, "" );
|
|
}
|
|
}
|
|
|
|
static void UI_Controls_ParseKeysList( void )
|
|
{
|
|
char *afile = (char *)LOAD_FILE( "gfx/shell/kb_act.lst", NULL );
|
|
char *pfile = afile;
|
|
char token[1024];
|
|
int i = 0;
|
|
|
|
if( !afile )
|
|
{
|
|
for( ; i < MAX_KEYS; i++ ) uiControls.keysDescriptionPtr[i] = NULL;
|
|
uiControls.keysList.itemNames = (const char **)uiControls.keysDescriptionPtr;
|
|
|
|
Con_Printf( "UI_Parse_KeysList: kb_act.lst not found\n" );
|
|
return;
|
|
}
|
|
|
|
while(( pfile = COM_ParseFile( pfile, token )) != NULL )
|
|
{
|
|
char str[128];
|
|
|
|
if( !stricmp( token, "blank" ))
|
|
{
|
|
// seperator
|
|
pfile = COM_ParseFile( pfile, token );
|
|
if( !pfile ) break; // technically an error
|
|
|
|
sprintf( str, "^6%s^7", token ); // enable uiPromptTextColor
|
|
StringConcat( uiControls.keysDescription[i], str, strlen( str ) + 1 );
|
|
StringConcat( uiControls.keysDescription[i], uiEmptyString, 256 ); // empty
|
|
uiControls.keysDescriptionPtr[i] = uiControls.keysDescription[i];
|
|
strcpy( uiControls.keysBind[i], "" );
|
|
strcpy( uiControls.firstKey[i], "" );
|
|
strcpy( uiControls.secondKey[i], "" );
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
// key definition
|
|
int keys[2];
|
|
|
|
UI_Controls_GetKeyBindings( token, keys );
|
|
strncpy( uiControls.keysBind[i], token, sizeof( uiControls.keysBind[i] ));
|
|
|
|
pfile = COM_ParseFile( pfile, token );
|
|
if( !pfile ) break; // technically an error
|
|
|
|
sprintf( str, "^6%s^7", token ); // enable uiPromptTextColor
|
|
|
|
if( keys[0] == -1 ) strcpy( uiControls.firstKey[i], "" );
|
|
else strncpy( uiControls.firstKey[i], KEY_KeynumToString( keys[0] ), sizeof( uiControls.firstKey[i] ));
|
|
|
|
if( keys[1] == -1 ) strcpy( uiControls.secondKey[i], "" );
|
|
else strncpy( uiControls.secondKey[i], KEY_KeynumToString( keys[1] ), sizeof( uiControls.secondKey[i] ));
|
|
|
|
StringConcat( uiControls.keysDescription[i], str, CMD_LENGTH );
|
|
StringConcat( uiControls.keysDescription[i], uiEmptyString, CMD_LENGTH );
|
|
|
|
// HACKHACK this color should be get from kb_keys.lst
|
|
if( !strnicmp( uiControls.firstKey[i], "MOUSE", 5 ))
|
|
sprintf( str, "^5%s^7", uiControls.firstKey[i] ); // cyan
|
|
else sprintf( str, "^3%s^7", uiControls.firstKey[i] ); // yellow
|
|
StringConcat( uiControls.keysDescription[i], str, KEY1_LENGTH );
|
|
StringConcat( uiControls.keysDescription[i], uiEmptyString, KEY1_LENGTH );
|
|
|
|
// HACKHACK this color should be get from kb_keys.lst
|
|
if( !strnicmp( uiControls.secondKey[i], "MOUSE", 5 ))
|
|
sprintf( str, "^5%s^7", uiControls.secondKey[i] );// cyan
|
|
else sprintf( str, "^3%s^7", uiControls.secondKey[i] ); // yellow
|
|
|
|
StringConcat( uiControls.keysDescription[i], str, KEY2_LENGTH );
|
|
StringConcat( uiControls.keysDescription[i], uiEmptyString, KEY2_LENGTH );
|
|
uiControls.keysDescriptionPtr[i] = uiControls.keysDescription[i];
|
|
i++;
|
|
}
|
|
}
|
|
|
|
FREE_FILE( afile );
|
|
|
|
for( ; i < MAX_KEYS; i++ ) uiControls.keysDescriptionPtr[i] = NULL;
|
|
uiControls.keysList.itemNames = (const char **)uiControls.keysDescriptionPtr;
|
|
}
|
|
|
|
static void UI_PromptDialog( void )
|
|
{
|
|
// toggle main menu between active\inactive
|
|
// show\hide quit dialog
|
|
uiControls.defaults.generic.flags ^= QMF_INACTIVE;
|
|
uiControls.advanced.generic.flags ^= QMF_INACTIVE;
|
|
uiControls.done.generic.flags ^= QMF_INACTIVE;
|
|
uiControls.cancel.generic.flags ^= QMF_INACTIVE;
|
|
uiControls.keysList.generic.flags ^= QMF_INACTIVE;
|
|
|
|
uiControls.msgBox.generic.flags ^= QMF_HIDDEN;
|
|
uiControls.dlgMessage.generic.flags ^= QMF_HIDDEN;
|
|
}
|
|
|
|
static void UI_Controls_RestartMenu( void )
|
|
{
|
|
int lastSelectedKey = uiControls.keysList.curItem;
|
|
int lastTopItem = uiControls.keysList.topItem;
|
|
|
|
// restarts the menu
|
|
UI_PopMenu();
|
|
UI_Controls_Menu();
|
|
|
|
// restore last key and top item
|
|
uiControls.keysList.curItem = lastSelectedKey;
|
|
uiControls.keysList.topItem = lastTopItem;
|
|
}
|
|
|
|
static void UI_Controls_ResetKeysList( void )
|
|
{
|
|
char *afile = (char *)LOAD_FILE( "gfx/shell/kb_def.lst", NULL );
|
|
char *pfile = afile;
|
|
char token[1024];
|
|
int i = 0;
|
|
|
|
if( !afile )
|
|
{
|
|
Con_Printf( "UI_Parse_KeysList: kb_act.lst not found\n" );
|
|
return;
|
|
}
|
|
|
|
while(( pfile = COM_ParseFile( pfile, token )) != NULL )
|
|
{
|
|
char key[32];
|
|
|
|
strncpy( key, token, sizeof( key ));
|
|
|
|
pfile = COM_ParseFile( pfile, token );
|
|
if( !pfile ) break; // technically an error
|
|
|
|
char cmd[128];
|
|
|
|
if( key[0] == '\\' && key[1] == '\\' )
|
|
{
|
|
key[0] = '\\';
|
|
key[1] = '\0';
|
|
}
|
|
|
|
UI_UnbindCommand( token );
|
|
|
|
sprintf( cmd, "bind \"%s\" \"%s\"\n", key, token );
|
|
CLIENT_COMMAND( TRUE, cmd );
|
|
}
|
|
|
|
FREE_FILE( afile );
|
|
UI_Controls_RestartMenu ();
|
|
}
|
|
|
|
/*
|
|
=================
|
|
UI_Controls_KeyFunc
|
|
=================
|
|
*/
|
|
static const char *UI_Controls_KeyFunc( int key, int down )
|
|
{
|
|
char cmd[128];
|
|
|
|
if( down )
|
|
{
|
|
if( uiControls.bind_grab ) // assume we are in grab-mode
|
|
{
|
|
// defining a key
|
|
if( key == '`' || key == '~' )
|
|
{
|
|
return uiSoundBuzz;
|
|
}
|
|
else if( key != K_ESCAPE )
|
|
{
|
|
const char *bindName = uiControls.keysBind[uiControls.keysList.curItem];
|
|
sprintf( cmd, "bind \"%s\" \"%s\"\n", KEY_KeynumToString( key ), bindName );
|
|
CLIENT_COMMAND( TRUE, cmd );
|
|
}
|
|
|
|
uiControls.bind_grab = false;
|
|
UI_Controls_RestartMenu();
|
|
|
|
return uiSoundLaunch;
|
|
}
|
|
|
|
if( key == K_ENTER && uiControls.dlgMessage.generic.flags & QMF_HIDDEN )
|
|
{
|
|
if( !strlen( uiControls.keysBind[uiControls.keysList.curItem] ))
|
|
{
|
|
// probably it's a seperator
|
|
return uiSoundBuzz;
|
|
}
|
|
|
|
// entering to grab-mode
|
|
const char *bindName = uiControls.keysBind[uiControls.keysList.curItem];
|
|
int keys[2];
|
|
|
|
UI_Controls_GetKeyBindings( bindName, keys );
|
|
if( keys[1] != -1 ) UI_UnbindCommand( bindName );
|
|
uiControls.bind_grab = true;
|
|
|
|
UI_PromptDialog(); // show prompt
|
|
return uiSoundKey;
|
|
}
|
|
|
|
if(( key == K_BACKSPACE || key == K_DEL ) && uiControls.dlgMessage.generic.flags & QMF_HIDDEN )
|
|
{
|
|
// delete bindings
|
|
|
|
if( !strlen( uiControls.keysBind[uiControls.keysList.curItem] ))
|
|
{
|
|
// probably it's a seperator
|
|
return uiSoundNull;
|
|
}
|
|
|
|
const char *bindName = uiControls.keysBind[uiControls.keysList.curItem];
|
|
UI_UnbindCommand( bindName );
|
|
UI_StartSound( uiSoundRemoveKey );
|
|
UI_Controls_RestartMenu();
|
|
|
|
return uiSoundNull;
|
|
}
|
|
}
|
|
return UI_DefaultKey( &uiControls.menu, key, down );
|
|
}
|
|
|
|
/*
|
|
=================
|
|
UI_MsgBox_Ownerdraw
|
|
=================
|
|
*/
|
|
static void UI_MsgBox_Ownerdraw( void *self )
|
|
{
|
|
menuCommon_s *item = (menuCommon_s *)self;
|
|
|
|
UI_FillRect( item->x, item->y, item->width, item->height, uiPromptBgColor );
|
|
}
|
|
|
|
/*
|
|
=================
|
|
UI_Controls_Callback
|
|
=================
|
|
*/
|
|
static void UI_Controls_Callback( void *self, int event )
|
|
{
|
|
menuCommon_s *item = (menuCommon_s *)self;
|
|
|
|
if( event != QM_ACTIVATED )
|
|
return;
|
|
|
|
switch( item->id )
|
|
{
|
|
case ID_DONE:
|
|
case ID_CANCEL:
|
|
UI_PopMenu();
|
|
break;
|
|
case ID_DEFAULTS:
|
|
UI_Controls_ResetKeysList ();
|
|
break;
|
|
case ID_ADVANCED:
|
|
UI_AdvControls_Menu();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
UI_Controls_Init
|
|
=================
|
|
*/
|
|
static void UI_Controls_Init( void )
|
|
{
|
|
memset( &uiControls, 0, sizeof( uiControls_t ));
|
|
|
|
uiControls.menu.vidInitFunc = UI_Controls_Init;
|
|
uiControls.menu.keyFunc = UI_Controls_KeyFunc;
|
|
|
|
StringConcat( uiControls.hintText, "Action", CMD_LENGTH );
|
|
StringConcat( uiControls.hintText, uiEmptyString, CMD_LENGTH-4 );
|
|
StringConcat( uiControls.hintText, "Key/Button", KEY1_LENGTH );
|
|
StringConcat( uiControls.hintText, uiEmptyString, KEY1_LENGTH-8 );
|
|
StringConcat( uiControls.hintText, "Alternate", KEY2_LENGTH );
|
|
StringConcat( uiControls.hintText, uiEmptyString, KEY2_LENGTH );
|
|
|
|
uiControls.background.generic.id = ID_BACKGROUND;
|
|
uiControls.background.generic.type = QMTYPE_BITMAP;
|
|
uiControls.background.generic.flags = QMF_INACTIVE;
|
|
uiControls.background.generic.x = 0;
|
|
uiControls.background.generic.y = 0;
|
|
uiControls.background.generic.width = 1024;
|
|
uiControls.background.generic.height = 768;
|
|
uiControls.background.pic = ART_BACKGROUND;
|
|
|
|
uiControls.banner.generic.id = ID_BANNER;
|
|
uiControls.banner.generic.type = QMTYPE_BITMAP;
|
|
uiControls.banner.generic.flags = QMF_INACTIVE|QMF_DRAW_ADDITIVE;
|
|
uiControls.banner.generic.x = UI_BANNER_POSX;
|
|
uiControls.banner.generic.y = UI_BANNER_POSY;
|
|
uiControls.banner.generic.width = UI_BANNER_WIDTH;
|
|
uiControls.banner.generic.height = UI_BANNER_HEIGHT;
|
|
uiControls.banner.pic = ART_BANNER;
|
|
|
|
uiControls.defaults.generic.id = ID_DEFAULTS;
|
|
uiControls.defaults.generic.type = QMTYPE_BM_BUTTON;
|
|
uiControls.defaults.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW;
|
|
uiControls.defaults.generic.x = 72;
|
|
uiControls.defaults.generic.y = 230;
|
|
uiControls.defaults.generic.name = "Use defaults";
|
|
uiControls.defaults.generic.statusText = "Reset all buttons binding to their default values";
|
|
uiControls.defaults.generic.callback = UI_Controls_Callback;
|
|
|
|
UI_UtilSetupPicButton( &uiControls.defaults, PC_USE_DEFAULTS );
|
|
|
|
uiControls.advanced.generic.id = ID_ADVANCED;
|
|
uiControls.advanced.generic.type = QMTYPE_BM_BUTTON;
|
|
uiControls.advanced.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW;
|
|
uiControls.advanced.generic.x = 72;
|
|
uiControls.advanced.generic.y = 280;
|
|
uiControls.advanced.generic.name = "Adv controls";
|
|
uiControls.advanced.generic.statusText = "Change mouse sensitivity, enable autoaim, mouselook and crosshair";
|
|
uiControls.advanced.generic.callback = UI_Controls_Callback;
|
|
|
|
UI_UtilSetupPicButton( &uiControls.advanced, PC_ADV_CONTROLS );
|
|
|
|
uiControls.done.generic.id = ID_DONE;
|
|
uiControls.done.generic.type = QMTYPE_BM_BUTTON;
|
|
uiControls.done.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW;
|
|
uiControls.done.generic.x = 72;
|
|
uiControls.done.generic.y = 330;
|
|
uiControls.done.generic.name = "Ok";
|
|
uiControls.done.generic.statusText = "Save changes and return to configuration menu";
|
|
uiControls.done.generic.callback = UI_Controls_Callback;
|
|
|
|
UI_UtilSetupPicButton( &uiControls.done, PC_DONE );
|
|
|
|
uiControls.cancel.generic.id = ID_CANCEL;
|
|
uiControls.cancel.generic.type = QMTYPE_BM_BUTTON;
|
|
uiControls.cancel.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW;
|
|
uiControls.cancel.generic.x = 72;
|
|
uiControls.cancel.generic.y = 380;
|
|
uiControls.cancel.generic.name = "Cancel";
|
|
uiControls.cancel.generic.statusText = "Discard changes and return to configuration menu";
|
|
uiControls.cancel.generic.callback = UI_Controls_Callback;
|
|
|
|
UI_UtilSetupPicButton( &uiControls.cancel, PC_CANCEL );
|
|
|
|
uiControls.hintMessage.generic.id = ID_TABLEHINT;
|
|
uiControls.hintMessage.generic.type = QMTYPE_ACTION;
|
|
uiControls.hintMessage.generic.flags = QMF_INACTIVE|QMF_SMALLFONT;
|
|
uiControls.hintMessage.generic.color = uiColorHelp;
|
|
uiControls.hintMessage.generic.name = uiControls.hintText;
|
|
uiControls.hintMessage.generic.x = 360;
|
|
uiControls.hintMessage.generic.y = 225;
|
|
|
|
uiControls.keysList.generic.id = ID_KEYLIST;
|
|
uiControls.keysList.generic.type = QMTYPE_SCROLLLIST;
|
|
uiControls.keysList.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_SMALLFONT;
|
|
uiControls.keysList.generic.x = 360;
|
|
uiControls.keysList.generic.y = 255;
|
|
uiControls.keysList.generic.width = 640;
|
|
uiControls.keysList.generic.height = 440;
|
|
uiControls.keysList.generic.callback = UI_Controls_Callback;
|
|
|
|
UI_Controls_ParseKeysList();
|
|
|
|
uiControls.msgBox.generic.id = ID_MSGBOX;
|
|
uiControls.msgBox.generic.type = QMTYPE_ACTION;
|
|
uiControls.msgBox.generic.flags = QMF_INACTIVE|QMF_HIDDEN;
|
|
uiControls.msgBox.generic.ownerdraw = UI_MsgBox_Ownerdraw; // just a fill rectangle
|
|
uiControls.msgBox.generic.x = 192;
|
|
uiControls.msgBox.generic.y = 256;
|
|
uiControls.msgBox.generic.width = 640;
|
|
uiControls.msgBox.generic.height = 128;
|
|
|
|
uiControls.dlgMessage.generic.id = ID_MSGTEXT;
|
|
uiControls.dlgMessage.generic.type = QMTYPE_ACTION;
|
|
uiControls.dlgMessage.generic.flags = QMF_INACTIVE|QMF_HIDDEN|QMF_DROPSHADOW;
|
|
uiControls.dlgMessage.generic.name = "Press a key or button";
|
|
uiControls.dlgMessage.generic.x = 320;
|
|
uiControls.dlgMessage.generic.y = 280;
|
|
|
|
UI_AddItem( &uiControls.menu, (void *)&uiControls.background );
|
|
UI_AddItem( &uiControls.menu, (void *)&uiControls.banner );
|
|
UI_AddItem( &uiControls.menu, (void *)&uiControls.defaults );
|
|
UI_AddItem( &uiControls.menu, (void *)&uiControls.advanced );
|
|
UI_AddItem( &uiControls.menu, (void *)&uiControls.done );
|
|
UI_AddItem( &uiControls.menu, (void *)&uiControls.cancel );
|
|
UI_AddItem( &uiControls.menu, (void *)&uiControls.hintMessage );
|
|
UI_AddItem( &uiControls.menu, (void *)&uiControls.keysList );
|
|
UI_AddItem( &uiControls.menu, (void *)&uiControls.msgBox );
|
|
UI_AddItem( &uiControls.menu, (void *)&uiControls.dlgMessage );
|
|
}
|
|
|
|
/*
|
|
=================
|
|
UI_Controls_Precache
|
|
=================
|
|
*/
|
|
void UI_Controls_Precache( void )
|
|
{
|
|
PIC_Load( ART_BACKGROUND );
|
|
PIC_Load( ART_BANNER );
|
|
}
|
|
|
|
/*
|
|
=================
|
|
UI_Controls_Menu
|
|
=================
|
|
*/
|
|
void UI_Controls_Menu( void )
|
|
{
|
|
UI_Controls_Precache();
|
|
UI_Controls_Init();
|
|
|
|
UI_PushMenu( &uiControls.menu );
|
|
} |