source-engine/gameui/OptionsSubAudio.cpp
2022-04-16 12:20:36 +03:00

437 lines
14 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "OptionsSubAudio.h"
#include "cvarslider.h"
#include "EngineInterface.h"
#include "ModInfo.h"
#include "vgui_controls/ComboBox.h"
#include "vgui_controls/QueryBox.h"
#include "CvarToggleCheckButton.h"
#include "tier1/KeyValues.h"
#include "tier1/convar.h"
#include <vgui/IInput.h>
#include <steam/steam_api.h>
#include <tier1/strtools.h>
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
// This member is static so that the updated audio language can be referenced during shutdown
char* COptionsSubAudio::m_pchUpdatedAudioLanguage = (char*)GetLanguageShortName( k_Lang_English );
enum SoundQuality_e
{
SOUNDQUALITY_LOW,
SOUNDQUALITY_MEDIUM,
SOUNDQUALITY_HIGH,
};
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
COptionsSubAudio::COptionsSubAudio(vgui::Panel *parent) : PropertyPage(parent, NULL)
{
m_pSFXSlider = new CCvarSlider( this, "SFXSlider", "#GameUI_SoundEffectVolume", 0.0f, 1.0f, "volume" );
m_pMusicSlider = new CCvarSlider( this, "MusicSlider", "#GameUI_MusicVolume", 0.0f, 1.0f, "Snd_MusicVolume" );
m_pCloseCaptionCombo = new ComboBox( this, "CloseCaptionCheck", 6, false );
m_pCloseCaptionCombo->AddItem( "#GameUI_NoClosedCaptions", NULL );
m_pCloseCaptionCombo->AddItem( "#GameUI_SubtitlesAndSoundEffects", NULL );
m_pCloseCaptionCombo->AddItem( "#GameUI_Subtitles", NULL );
m_pSoundQualityCombo = new ComboBox( this, "SoundQuality", 6, false );
m_pSoundQualityCombo->AddItem( "#GameUI_High", new KeyValues("SoundQuality", "quality", SOUNDQUALITY_HIGH) );
m_pSoundQualityCombo->AddItem( "#GameUI_Medium", new KeyValues("SoundQuality", "quality", SOUNDQUALITY_MEDIUM) );
m_pSoundQualityCombo->AddItem( "#GameUI_Low", new KeyValues("SoundQuality", "quality", SOUNDQUALITY_LOW) );
m_pSpeakerSetupCombo = new ComboBox( this, "SpeakerSetup", 6, false );
#ifndef POSIX
m_pSpeakerSetupCombo->AddItem( "#GameUI_Headphones", new KeyValues("SpeakerSetup", "speakers", 0) );
#endif
m_pSpeakerSetupCombo->AddItem( "#GameUI_2Speakers", new KeyValues("SpeakerSetup", "speakers", 2) );
#ifndef POSIX
m_pSpeakerSetupCombo->AddItem( "#GameUI_4Speakers", new KeyValues("SpeakerSetup", "speakers", 4) );
m_pSpeakerSetupCombo->AddItem( "#GameUI_5Speakers", new KeyValues("SpeakerSetup", "speakers", 5) );
m_pSpeakerSetupCombo->AddItem( "#GameUI_7Speakers", new KeyValues("SpeakerSetup", "speakers", 7) );
#endif
m_pSpokenLanguageCombo = new ComboBox (this, "AudioSpokenLanguage", 6, false );
m_pSoundMuteLoseFocusCheckButton = new CCvarToggleCheckButton( this, "snd_mute_losefocus", "#GameUI_SndMuteLoseFocus", "snd_mute_losefocus" );
LoadControlSettings("Resource\\OptionsSubAudio.res");
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
COptionsSubAudio::~COptionsSubAudio()
{
}
//-----------------------------------------------------------------------------
// Purpose: Reloads data
//-----------------------------------------------------------------------------
void COptionsSubAudio::OnResetData()
{
m_bRequireRestart = false;
m_pSFXSlider->Reset();
m_pMusicSlider->Reset();
// reset the combo boxes
// close captions
ConVarRef closecaption("closecaption");
ConVarRef cc_subtitles("cc_subtitles");
if (closecaption.GetBool())
{
if (cc_subtitles.GetBool())
{
m_pCloseCaptionCombo->ActivateItem(2);
}
else
{
m_pCloseCaptionCombo->ActivateItem(1);
}
}
else
{
m_pCloseCaptionCombo->ActivateItem(0);
}
// speakers
ConVarRef snd_surround_speakers("Snd_Surround_Speakers");
int speakers = snd_surround_speakers.GetInt();
#ifdef POSIX
// On Posix there is no headphone option, so we upgrade to 2 speakers if Snd_Surround_Speakers == 0
if ( speakers == 0 )
speakers = 2;
#endif
// if Snd_Surround_Speakers is -1, then upgrade to 2 speakers
if ( speakers < 0 )
speakers = 2;
{for (int itemID = 0; itemID < m_pSpeakerSetupCombo->GetItemCount(); itemID++)
{
KeyValues *kv = m_pSpeakerSetupCombo->GetItemUserData( itemID );
if (kv && kv->GetInt( "speakers" ) == speakers)
{
m_pSpeakerSetupCombo->ActivateItem( itemID );
break;
}
}}
// sound quality is made up from several cvars
ConVarRef Snd_PitchQuality("Snd_PitchQuality");
ConVarRef dsp_slow_cpu("dsp_slow_cpu");
int quality = SOUNDQUALITY_LOW;
if (dsp_slow_cpu.GetBool() == false)
{
quality = SOUNDQUALITY_MEDIUM;
}
if (Snd_PitchQuality.GetBool())
{
quality = SOUNDQUALITY_HIGH;
}
// find the item in the list and activate it
{for (int itemID = 0; itemID < m_pSoundQualityCombo->GetItemCount(); itemID++)
{
KeyValues *kv = m_pSoundQualityCombo->GetItemUserData(itemID);
if (kv && kv->GetInt("quality") == quality)
{
m_pSoundQualityCombo->ActivateItem(itemID);
}
}}
//
// Audio Languages
//
char szCurrentLanguage[50];
char szAvailableLanguages[512];
szCurrentLanguage[0] = 0;
szAvailableLanguages[0] = 0;
// Fallback to current engine language
engine->GetUILanguage( szCurrentLanguage, sizeof( szCurrentLanguage ));
// In a Steam environment we get the current language
#if !defined( NO_STEAM )
// When Steam isn't running we can't get the language info...
if ( steamapicontext->SteamApps() )
{
Q_strncpy( szCurrentLanguage, steamapicontext->SteamApps()->GetCurrentGameLanguage(), sizeof(szCurrentLanguage) );
Q_strncpy( szAvailableLanguages, steamapicontext->SteamApps()->GetAvailableGameLanguages(), sizeof(szAvailableLanguages) );
}
#endif
// Get the spoken language and store it for comparison purposes
m_nCurrentAudioLanguage = PchLanguageToELanguage( szCurrentLanguage );
// Check to see if we have a list of languages from Steam
if ( V_strlen( szAvailableLanguages ) )
{
// Populate the combo box with each available language
CUtlVector<char*> languagesList;
V_SplitString( szAvailableLanguages, ",", languagesList );
for ( int i=0; i < languagesList.Count(); i++ )
{
const ELanguage languageCode = PchLanguageToELanguage( languagesList[i] );
m_pSpokenLanguageCombo->AddItem( GetLanguageVGUILocalization( languageCode ), new KeyValues ("Audio Languages", "language", languageCode) );
}
languagesList.PurgeAndDeleteElements();
}
else
{
// Add the current language to the combo
m_pSpokenLanguageCombo->AddItem( GetLanguageVGUILocalization( m_nCurrentAudioLanguage ), new KeyValues ("Audio Languages", "language", m_nCurrentAudioLanguage) );
}
// Activate the current language in the combo
{for (int itemID = 0; itemID < m_pSpokenLanguageCombo->GetItemCount(); itemID++)
{
KeyValues *kv = m_pSpokenLanguageCombo->GetItemUserData( itemID );
if ( kv && kv->GetInt( "language" ) == m_nCurrentAudioLanguage )
{
m_pSpokenLanguageCombo->ActivateItem( itemID );
break;
}
}}
m_pSoundMuteLoseFocusCheckButton->Reset();
}
//-----------------------------------------------------------------------------
// Purpose: Applies changes
//-----------------------------------------------------------------------------
void COptionsSubAudio::OnApplyChanges()
{
m_pSFXSlider->ApplyChanges();
m_pMusicSlider->ApplyChanges();
// set the cvars appropriately
// Tracker 28933: Note we can't do this because closecaption is marked
// FCVAR_USERINFO and it won't get sent to server is we direct set it, we
// need to pass it along to the engine parser!!!
// ConVar *closecaption = (ConVar *)cvar->FindVar("closecaption");
int closecaption_value = 0;
ConVarRef cc_subtitles( "cc_subtitles" );
switch (m_pCloseCaptionCombo->GetActiveItem())
{
default:
case 0:
closecaption_value = 0;
cc_subtitles.SetValue( 0 );
break;
case 1:
closecaption_value = 1;
cc_subtitles.SetValue( 0 );
break;
case 2:
closecaption_value = 1;
cc_subtitles.SetValue( 1 );
break;
}
// Stuff the close caption change to the console so that it can be
// sent to the server (FCVAR_USERINFO) so that you don't have to restart
// the level for the change to take effect.
char cmd[ 64 ];
Q_snprintf( cmd, sizeof( cmd ), "closecaption %i\n", closecaption_value );
engine->ClientCmd_Unrestricted( cmd );
ConVarRef snd_surround_speakers( "Snd_Surround_Speakers" );
int speakers = m_pSpeakerSetupCombo->GetActiveItemUserData()->GetInt( "speakers" );
snd_surround_speakers.SetValue( speakers );
// quality
ConVarRef Snd_PitchQuality( "Snd_PitchQuality" );
ConVarRef dsp_slow_cpu( "dsp_slow_cpu" );
int quality = m_pSoundQualityCombo->GetActiveItemUserData()->GetInt( "quality" );
switch ( quality )
{
case SOUNDQUALITY_LOW:
dsp_slow_cpu.SetValue(true);
Snd_PitchQuality.SetValue(false);
break;
case SOUNDQUALITY_MEDIUM:
dsp_slow_cpu.SetValue(false);
Snd_PitchQuality.SetValue(false);
break;
default:
Assert("Undefined sound quality setting.");
case SOUNDQUALITY_HIGH:
dsp_slow_cpu.SetValue(false);
Snd_PitchQuality.SetValue(true);
break;
};
// headphones at high quality get enhanced stereo turned on
ConVarRef dsp_enhance_stereo( "dsp_enhance_stereo" );
if (speakers == 0 && quality == SOUNDQUALITY_HIGH)
{
dsp_enhance_stereo.SetValue( 1 );
}
else
{
dsp_enhance_stereo.SetValue( 0 );
}
// Audio spoken language
KeyValues *kv = m_pSpokenLanguageCombo->GetItemUserData( m_pSpokenLanguageCombo->GetActiveItem() );
const ELanguage nUpdatedAudioLanguage = (ELanguage)( kv ? kv->GetInt( "language" ) : k_Lang_English );
if ( nUpdatedAudioLanguage != m_nCurrentAudioLanguage )
{
// Store new language in static member so that it can be accessed during shutdown when this instance is gone
m_pchUpdatedAudioLanguage = (char *) GetLanguageShortName( nUpdatedAudioLanguage );
// Inform user that they need to restart in order change language at this time
QueryBox *qb = new QueryBox( "#GameUI_ChangeLanguageRestart_Title", "#GameUI_ChangeLanguageRestart_Info", GetParent()->GetParent()->GetParent() );
if (qb != NULL)
{
qb->SetOKCommand( new KeyValues( "Command", "command", "RestartWithNewLanguage" ) );
qb->SetOKButtonText( "#GameUI_ChangeLanguageRestart_OkButton" );
qb->SetCancelButtonText( "#GameUI_ChangeLanguageRestart_CancelButton" );
qb->AddActionSignalTarget( GetParent()->GetParent()->GetParent() );
qb->DoModal();
}
}
m_pSoundMuteLoseFocusCheckButton->ApplyChanges();
}
//-----------------------------------------------------------------------------
// Purpose: Called on controls changing, enables the Apply button
//-----------------------------------------------------------------------------
void COptionsSubAudio::OnControlModified()
{
PostActionSignal(new KeyValues("ApplyButtonEnable"));
}
//-----------------------------------------------------------------------------
// Purpose: returns true if the engine needs to be restarted
//-----------------------------------------------------------------------------
bool COptionsSubAudio::RequiresRestart()
{
// nothing in audio requires a restart like now
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void COptionsSubAudio::OnCommand( const char *command )
{
if ( !stricmp( command, "TestSpeakers" ) )
{
// ask them if they REALLY want to test the speakers if they're in a game already.
if (engine->IsConnected())
{
QueryBox *qb = new QueryBox("#GameUI_TestSpeakersWarning_Title", "#GameUI_TestSpeakersWarning_Info" );
if (qb != NULL)
{
qb->SetOKCommand(new KeyValues("RunTestSpeakers"));
qb->SetOKButtonText("#GameUI_TestSpeakersWarning_OkButton");
qb->SetCancelButtonText("#GameUI_TestSpeakersWarning_CancelButton");
qb->AddActionSignalTarget( this );
qb->DoModal();
}
else
{
// couldn't create the warning dialog for some reason, so just test the speakers.
RunTestSpeakers();
}
}
else
{
// player isn't connected to a game so there's no reason to warn them about being disconnected.
// create the command to execute
RunTestSpeakers();
}
}
BaseClass::OnCommand( command );
}
//-----------------------------------------------------------------------------
// Purpose: Run the test speakers map.
//-----------------------------------------------------------------------------
void COptionsSubAudio::RunTestSpeakers()
{
engine->ClientCmd_Unrestricted( "disconnect\nwait\nwait\nsv_lan 1\nsetmaster enable\nmaxplayers 1\n\nhostname \"Speaker Test\"\nprogress_enable\nmap test_speakers\n" );
}
//-----------------------------------------------------------------------------
// Purpose: third-party audio credits dialog
//-----------------------------------------------------------------------------
class COptionsSubAudioThirdPartyCreditsDlg : public vgui::Frame
{
DECLARE_CLASS_SIMPLE(COptionsSubAudioThirdPartyCreditsDlg, vgui::Frame);
public:
COptionsSubAudioThirdPartyCreditsDlg(vgui::VPANEL hParent) : BaseClass(NULL, NULL)
{
// parent is ignored, since we want look like we're steal focus from the parent (we'll become modal below)
int w = 500;
int h = 200;
if (ipanel()->IsProportional(hParent))
{
SetProportional(true);
w = scheme()->GetProportionalScaledValueEx(GetScheme(), w);
h = scheme()->GetProportionalScaledValueEx(GetScheme(), h);
}
SetTitle("#GameUI_ThirdPartyAudio_Title", true);
SetSize(w, h);
LoadControlSettings("resource/OptionsSubAudioThirdPartyDlg.res");
MoveToCenterOfScreen();
SetSizeable(false);
SetDeleteSelfOnClose(true);
}
virtual void Activate()
{
BaseClass::Activate();
input()->SetAppModalSurface(GetVPanel());
}
void OnKeyCodeTyped(KeyCode code)
{
// force ourselves to be closed if the escape key it pressed
if (code == KEY_ESCAPE)
{
Close();
}
else
{
BaseClass::OnKeyCodeTyped(code);
}
}
};
//-----------------------------------------------------------------------------
// Purpose: Open third party audio credits dialog
//-----------------------------------------------------------------------------
void COptionsSubAudio::OpenThirdPartySoundCreditsDialog()
{
if (!m_OptionsSubAudioThirdPartyCreditsDlg.Get())
{
m_OptionsSubAudioThirdPartyCreditsDlg = new COptionsSubAudioThirdPartyCreditsDlg(GetVParent());
}
m_OptionsSubAudioThirdPartyCreditsDlg->Activate();
}