This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/mainui/menu_controls.cpp
2022-06-27 01:15:15 +03:00

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 );
}