import class gameuiSettingsMenuGameController extends gameuiMenuGameController
{
	public import function RunGraphicsBenchmark();
	public import function IsBenchmarkPossible() : Bool;
	public import function CanEditSafezones() : Bool;

	protected virtual function SetLanguagePackageInstallProgress( progress : Float ) {}

	protected virtual function SetLanguagePackageInstallProgressBar( progress : Float, completed : Bool, started : Bool ) {}
}

struct SettingsCategory
{
	var label : CName;
	var subcategories : array< SettingsCategory >;
	var options : array< ConfigVar >;
	var isEmpty : Bool;
	default isEmpty = true;
	var groupPath : CName;
}

enum SettingsType
{
	Slider = 0,
	Toggle = 1,
	DropdownList = 2,
}

class SettingsCategoryController extends inkLogicController
{
	protected editable var m_label : inkTextRef;

	public function Setup( label : CName )
	{
		var labelString : String;
		labelString = GetLocalizedTextByKey( label );
		if( StrLen( labelString ) == 0 )
		{
			labelString = "<Not Localized> " + ( ( String )( label ) );
		}
		inkTextRef.SetText( m_label, labelString );
	}

}

class SettingsVarListener extends ConfigVarListener
{
	private var m_ctrl : weak< SettingsMainGameController >;

	public function RegisterController( ctrl : SettingsMainGameController )
	{
		m_ctrl = ctrl;
	}

	public export override function OnVarModified( groupPath : CName, varName : CName, varType : ConfigVarType, reason : ConfigChangeReason )
	{
		m_ctrl.OnVarModified( groupPath, varName, varType, reason );
	}

}

class SettingsNotificationListener extends ConfigNotificationListener
{
	private var m_ctrl : weak< SettingsMainGameController >;

	public function RegisterController( ctrl : SettingsMainGameController )
	{
		m_ctrl = ctrl;
	}

	public export override function OnNotify( status : ConfigNotificationType )
	{
		m_ctrl.OnSettingsNotify( status );
	}

}

class SettingsMenuUserData extends gameuiMenuGameController
{
	var m_isDlcSettings : Bool;
	var m_isBenchmarkSettings : Bool;
	default m_isBenchmarkSettings = false;
}

class SettingsMainGameController extends gameuiSettingsMenuGameController
{
	[ category = "Main" ]
	private editable var m_scrollPanel : inkWidgetRef;
	[ category = "Main" ]
	private editable var m_selectorWidget : inkWidgetRef;
	[ category = "Main" ]
	private editable var m_buttonHintsManagerRef : inkWidgetRef;
	[ category = "Main" ]
	private editable var m_settingsOptionsList : inkCompoundRef;
	[ category = "Bottom Buttons" ]
	private editable var m_applyButton : inkWidgetRef;
	[ category = "Bottom Buttons" ]
	private editable var m_resetButton : inkWidgetRef;
	[ category = "Bottom Buttons" ]
	private editable var m_defaultButton : inkWidgetRef;
	[ category = "Extra Buttons" ]
	private editable var m_benchmarkButton : inkWidgetRef;
	[ category = "Extra Buttons" ]
	private editable var m_brightnessButton : inkWidgetRef;
	[ category = "Extra Buttons" ]
	private editable var m_hdrButton : inkWidgetRef;
	[ category = "Extra Buttons" ]
	private editable var m_controllerButton : inkWidgetRef;
	[ category = "Extra Buttons" ]
	private editable var m_safezonesButton : inkWidgetRef;
	[ category = "Extra Buttons" ]
	private editable var m_replayTutorialButton : inkWidgetRef;
	[ category = "Right Side" ]
	private editable var m_languageInstallProgressBarRoot : inkWidgetRef;
	[ category = "Right Side" ]
	private editable var m_languageDisclaimer : inkWidgetRef;
	[ category = "Right Side" ]
	private editable var m_descriptionText : inkTextRef;
	[ category = "Setting Groups Names" ]
	private editable var m_settingGroupName_Video : CName;
	default m_settingGroupName_Video = '/video';
	[ category = "Setting Groups Names" ]
	private editable var m_settingGroupName_Graphics : CName;
	default m_settingGroupName_Graphics = '/graphics';
	[ category = "Setting Groups Names" ]
	private editable var m_settingGroupName_Interface : CName;
	default m_settingGroupName_Interface = '/interface';
	[ category = "Setting Groups Names" ]
	private editable var m_settingGroupName_Controls : CName;
	default m_settingGroupName_Controls = '/controls';
	[ category = "Setting Groups Names" ]
	private editable var m_settingGroupName_Language : CName;
	default m_settingGroupName_Language = '/language';
	[ category = "Setting Groups Names" ]
	private editable var m_settingGroupName_KeyBindings : CName;
	default m_settingGroupName_KeyBindings = '/key_bindings';
	[ category = "Other" ]
	private editable var m_descriptionWarningRichColor : String;
	private var m_languageInstallProgressBar : weak< SettingsLanguageInstallProgressBar >;
	private var m_menuEventDispatcher : weak< inkMenuEventDispatcher >;
	private var m_settingsElements : array< weak< SettingsSelectorController > >;
	private var m_buttonHintsController : weak< ButtonHints >;
	private var m_data : array< SettingsCategory >;
	private var m_menusList : array< CName >;
	private var m_settingsListener : SettingsVarListener;
	private var m_settingsNotificationListener : SettingsNotificationListener;
	private var m_settings : UserSettings;
	private var m_isPreGame : Bool;
	private var m_benchmarkNotificationToken : inkGameNotificationToken;
	private var m_safezonesEditorToken : inkGameNotificationToken;
	private var m_applyButtonEnabled : Bool;
	private var m_resetButtonEnabled : Bool;
	private var m_closeSettingsRequest : Bool;
	private var m_resetSettingsRequest : Bool;
	private var m_isDlcSettings : Bool;
	private var m_isBenchmarkSettings : Bool;
	private var m_showHdrButton : Bool;
	private var m_showBrightnessButton : Bool;
	private var m_useRightAligned : Bool;
	private var m_currentHDRindex : Int32;
	private var m_selectorCtrl : weak< ListController >;

	protected event OnInitialize()
	{
		m_settings = GetSystemRequestsHandler().GetUserSettings();
		m_isPreGame = GetSystemRequestsHandler().IsPreGame();
		m_settingsListener = new SettingsVarListener;
		m_settingsListener.RegisterController( this );
		m_settingsNotificationListener = new SettingsNotificationListener;
		m_settingsNotificationListener.RegisterController( this );
		m_settingsNotificationListener.Register();
		m_languageInstallProgressBar = ( ( SettingsLanguageInstallProgressBar )( inkWidgetRef.GetControllerByType( m_languageInstallProgressBarRoot, 'SettingsLanguageInstallProgressBar' ) ) );
		if( !( m_isDlcSettings ) )
		{
			RegisterToGlobalInputCallback( 'OnPostOnRelease', this, 'OnButtonRelease' );
			inkWidgetRef.GetControllerByType( m_applyButton, 'inkButtonController' ).RegisterToCallback( 'OnButtonClick', this, 'OnApplyButtonReleased' );
			inkWidgetRef.GetControllerByType( m_resetButton, 'inkButtonController' ).RegisterToCallback( 'OnButtonClick', this, 'OnResetButtonReleased' );
			inkWidgetRef.GetControllerByType( m_brightnessButton, 'inkButtonController' ).RegisterToCallback( 'OnButtonClick', this, 'OnBrightnessButtonReleased' );
			inkWidgetRef.GetControllerByType( m_hdrButton, 'inkButtonController' ).RegisterToCallback( 'OnButtonClick', this, 'OnHDRButtonReleased' );
			inkWidgetRef.GetControllerByType( m_controllerButton, 'inkButtonController' ).RegisterToCallback( 'OnButtonClick', this, 'OnControllerButtonReleased' );
			inkWidgetRef.RegisterToCallback( m_replayTutorialButton, 'OnPress', this, 'OnPressReplayTutorial' );
			inkWidgetRef.GetControllerByType( m_benchmarkButton, 'inkButtonController' ).RegisterToCallback( 'OnButtonClick', this, 'OnBenchmarkButtonReleased' );
			inkWidgetRef.GetControllerByType( m_safezonesButton, 'inkButtonController' ).RegisterToCallback( 'OnButtonClick', this, 'OnSafezonesButtonReleased' );
			inkWidgetRef.GetControllerByType( m_defaultButton, 'inkButtonController' ).RegisterToCallback( 'OnButtonClick', this, 'OnDefaultButtonReleased' );
			if( !( IsBenchmarkPossible() ) )
			{
				inkWidgetRef.SetVisible( m_benchmarkButton, false );
			}
			if( !( CanEditSafezones() ) )
			{
				inkWidgetRef.SetVisible( m_safezonesButton, false );
			}
		}
		else
		{
			inkWidgetRef.SetVisible( m_defaultButton, false );
			inkWidgetRef.SetVisible( m_controllerButton, false );
			inkWidgetRef.SetVisible( m_replayTutorialButton, false );
		}
		m_selectorCtrl = ( ( ListController )( inkWidgetRef.GetController( m_selectorWidget ) ) );
		m_selectorCtrl.RegisterToCallback( 'OnItemActivated', this, 'OnMenuChanged' );
		m_buttonHintsController = ( ( ButtonHints )( SpawnFromExternal( inkWidgetRef.Get( m_buttonHintsManagerRef ), R"base\gameplay\gui\common\buttonhints.inkwidget", 'Root' ).GetController() ) );
		PopulateHints();
		PopulateSettingsData();
		PopulateCategories( m_settings.GetMenuIndex() );
		CheckButtons();
		CheckDualSenseSettingsVisibility();
		CheckHDRSettingVisibility();
		SetLanguageDisclaimerVisiblity( m_settings.GetMenuIndex() );
		SetSideButtonsVisiblity( m_settings.GetMenuIndex() );
		PlayLibraryAnimation( 'intro' );
		m_closeSettingsRequest = false;
		m_resetSettingsRequest = false;
		m_useRightAligned = UseRightAligned();
		if( m_isPreGame )
		{
			GetSystemRequestsHandler().RequestTelemetryConsent( true );
		}
	}

	protected event OnSetUserData( userData : IScriptable )
	{
		var settingsUserData : SettingsMenuUserData;
		settingsUserData = ( ( SettingsMenuUserData )( userData ) );
		if( settingsUserData )
		{
			m_isDlcSettings = settingsUserData.m_isDlcSettings;
			m_isBenchmarkSettings = settingsUserData.m_isBenchmarkSettings;
		}
	}

	protected event OnUninitialize()
	{
		UnregisterFromGlobalInputCallback( 'OnPostOnRelease', this, 'OnButtonRelease' );
		m_menuEventDispatcher.UnregisterFromEvent( 'OnBack', this, 'OnBack' );
		m_selectorCtrl.UnregisterFromCallback( 'OnItemActivated', this, 'OnMenuChanged' );
		inkWidgetRef.GetControllerByType( m_applyButton, 'inkButtonController' ).UnregisterFromCallback( 'OnButtonClick', this, 'OnApplyButtonReleased' );
		inkWidgetRef.GetControllerByType( m_resetButton, 'inkButtonController' ).UnregisterFromCallback( 'OnButtonClick', this, 'OnResetButtonReleased' );
		inkWidgetRef.GetControllerByType( m_brightnessButton, 'inkButtonController' ).UnregisterFromCallback( 'OnButtonClick', this, 'OnBrightnessButtonReleased' );
		inkWidgetRef.GetControllerByType( m_controllerButton, 'inkButtonController' ).UnregisterFromCallback( 'OnButtonClick', this, 'OnControllerButtonReleased' );
		inkWidgetRef.UnregisterFromCallback( m_replayTutorialButton, 'OnPress', this, 'OnPressReplayTutorial' );
		inkWidgetRef.GetControllerByType( m_benchmarkButton, 'inkButtonController' ).UnregisterFromCallback( 'OnButtonClick', this, 'OnBenchmarkButtonReleased' );
		inkWidgetRef.GetControllerByType( m_safezonesButton, 'inkButtonController' ).UnregisterFromCallback( 'OnButtonClick', this, 'OnSafezonesButtonReleased' );
		inkWidgetRef.GetControllerByType( m_defaultButton, 'inkButtonController' ).UnregisterFromCallback( 'OnButtonClick', this, 'OnDefaultButtonReleased' );
	}

	public function EnableApplyButton()
	{
		inkWidgetRef.SetVisible( m_applyButton, true );
		m_applyButtonEnabled = true;
	}

	public function DisableApplyButton()
	{
		m_applyButtonEnabled = false;
		inkWidgetRef.SetVisible( m_applyButton, false );
	}

	public function IsApplyButtonEnabled() : Bool
	{
		return m_applyButtonEnabled;
	}

	public function EnableResetButton()
	{
		m_resetButtonEnabled = true;
		inkWidgetRef.SetVisible( m_resetButton, true );
	}

	public function DisableResetButton()
	{
		m_resetButtonEnabled = false;
		inkWidgetRef.SetVisible( m_resetButton, false );
	}

	public function IsResetButtonEnabled() : Bool
	{
		return m_resetButtonEnabled;
	}

	public function CheckButtons()
	{
		if( !( m_isDlcSettings ) && ( ( m_settings.NeedsConfirmation() || m_settings.NeedsRestartToApply() ) || m_settings.NeedsLoadLastCheckpoint() ) )
		{
			EnableApplyButton();
			EnableResetButton();
		}
		else
		{
			DisableApplyButton();
			DisableResetButton();
		}
		if( m_isBenchmarkSettings )
		{
			inkWidgetRef.SetVisible( m_controllerButton, false );
			inkWidgetRef.SetVisible( m_replayTutorialButton, false );
		}
	}

	public function OnVarModified( groupPath : CName, varName : CName, varType : ConfigVarType, reason : ConfigChangeReason )
	{
		var i : Int32;
		var size : Int32;
		var item : SettingsSelectorController;
		size = m_settingsElements.Size();
		CheckButtons();
		for( i = 0; i < size; i += 1 )
		{
			item = m_settingsElements[ i ];
			if( item.GetGroupPath() == groupPath && item.GetVarName() == varName )
			{
				item.Refresh();
			}
		}
		if( varName == 'VoiceOver' )
		{
			SetLanguageDisclaimerVisiblity( m_settings.GetMenuIndex() );
		}
		if( varName == 'OnScreen' )
		{
			m_useRightAligned = UseRightAligned();
		}
		if( varName == 'BigFont' )
		{
			PopulateCategorySettingsOptions( m_settings.GetMenuIndex() );
			PopulateHints();
		}
		if( varName == 'HDRModes' )
		{
			CheckHDRSettingVisibility();
		}
	}

	private function SetLanguageDisclaimerVisiblity( i : Int32 )
	{
		var voName : CName;
		var voVar : ConfigVarListName;
		if( !( m_isBenchmarkSettings ) && m_menusList[ i ] == m_settingGroupName_Language )
		{
			voVar = ( ( ConfigVarListName )( m_settings.GetVar( m_settingGroupName_Language, 'VoiceOver' ) ) );
			voName = voVar.GetValue();
			if( voName == 'ru-ru' )
			{
				inkWidgetRef.SetVisible( m_languageDisclaimer, true );
			}
			else
			{
				inkWidgetRef.SetVisible( m_languageDisclaimer, false );
			}
		}
		else
		{
			inkWidgetRef.SetVisible( m_languageDisclaimer, false );
		}
	}

	private function UseRightAligned() : Bool
	{
		var langVar : ConfigVarListName;
		var langName : CName;
		langVar = ( ( ConfigVarListName )( m_settings.GetVar( m_settingGroupName_Language, 'OnScreen' ) ) );
		langName = langVar.GetValue();
		return langName == 'ar-ar';
	}

	public function OnSettingsNotify( status : ConfigNotificationType )
	{
		switch( status )
		{
			case ConfigNotificationType.Saved:
			case ConfigNotificationType.ChangesApplied:
			case ConfigNotificationType.RestartRequiredConfirmed:
			{
				if( m_closeSettingsRequest )
				{
					RequestClose();
				}
				else
				{
					CheckSettings();
					PopulateSettingsData();
					PopulateCategorySettingsOptions( -1 );
					RefreshInputIcons();
				}
				break;
			}
			;
			case ConfigNotificationType.ChangesLoadLastCheckpointApplied:
			{
				CheckSettings();
				PopulateSettingsData();
				PopulateCategorySettingsOptions( -1 );
				GameInstance.GetTelemetrySystem( GetPlayerControlledObject().GetGame() ).LogLastCheckpointLoaded();
				GetSystemRequestsHandler().LoadLastCheckpoint( true );
				RefreshInputIcons();
				break;
			}
			case ConfigNotificationType.ChangesRejected:
			case ConfigNotificationType.RestartRequiredRejected:
			case ConfigNotificationType.ChangesLoadLastCheckpointRejected:
			{
				if( m_closeSettingsRequest )
				{
					RequestClose();
				}
				else
				{
					CheckSettings();
					PopulateSettingsData();
					PopulateCategorySettingsOptions( -1 );
					RefreshInputIcons();
				}
				break;
			}
			;
			case ConfigNotificationType.ErrorSaving:
			{
				RequestClose();
				break;
			}
			case ConfigNotificationType.Refresh:
			{
				PopulateSettingsData();
				PopulateCategorySettingsOptions( -1 );
				RefreshInputIcons();
				break;
			}
		}
		CheckHDRSettingVisibility();
		CheckDualSenseSettingsVisibility();
	}

	private function CheckDualSenseSettingsVisibility()
	{
		var triggerEnabledVar : ConfigVarBool;
		var triggerIntensityVar : ConfigVarFloat;
		var isUsingDualSense : Bool;
		if( GetPlatformShortName() == "windows" )
		{
			triggerEnabledVar = ( ( ConfigVarBool )( m_settings.GetVar( '/accessibility/controls', 'EnableAdaptiveTriggerEffects' ) ) );
			triggerIntensityVar = ( ( ConfigVarFloat )( m_settings.GetVar( '/accessibility/controls', 'AdaptiveTriggersIntensity' ) ) );
			isUsingDualSense = GetPlayerControlledObject().PlayerLastUsedPS5Pad();
			triggerEnabledVar.SetVisible( isUsingDualSense );
			triggerIntensityVar.SetVisible( isUsingDualSense );
		}
	}

	private function CheckHDRSettingVisibility()
	{
		var i : Int32;
		var size : Int32;
		var item : SettingsSelectorController;
		var option : ConfigVarListString;
		var values : array< String >;
		var isEnabled : Bool;
		size = m_settingsElements.Size();
		option = ( ( ConfigVarListString )( m_settings.GetVar( '/video/display', 'HDRModes' ) ) );
		values = option.GetValues();
		if( !( option.HasRequestedValue() ) )
		{
			m_currentHDRindex = option.GetIndex();
			m_showBrightnessButton = m_currentHDRindex == 0;
			m_showHdrButton = !( m_showBrightnessButton );
			isEnabled = values.Size() > 1;
			option.SetEnabled( isEnabled );
			for( i = 0; i < size; i += 1 )
			{
				item = m_settingsElements[ i ];
				if( item.GetGroupPath() == '/video/display' && item.GetVarName() == 'HDRModes' )
				{
					item.GetRootWidget().SetState( ( ( isEnabled ) ? ( 'Default' ) : ( 'Disabled' ) ) );
					item.GetRootWidget().SetInteractive( isEnabled );
				}
			}
			SetSideButtonsVisiblity( m_settings.GetMenuIndex() );
		}
	}

	protected override function SetLanguagePackageInstallProgress( progress : Float )
	{
		m_languageInstallProgressBar.SetProgress( progress );
	}

	protected override function SetLanguagePackageInstallProgressBar( progress : Float, completed : Bool, started : Bool )
	{
		m_languageInstallProgressBar.SetProgressBarVisiblity( !( completed ) && started );
		m_languageInstallProgressBar.SetProgress( progress );
	}

	private function AddSettingsGroup( settingsGroup : ConfigGroup )
	{
		var settingsGroups : array< ConfigGroup >;
		var category : SettingsCategory;
		var currentSubcategory : SettingsCategory;
		var currentSettingsGroup : ConfigGroup;
		var i : Int32;
		category.label = settingsGroup.GetDisplayName();
		category.groupPath = settingsGroup.GetPath();
		if( settingsGroup.HasVars( m_isPreGame || m_isBenchmarkSettings ) )
		{
			category.options = settingsGroup.GetVars( m_isPreGame || m_isBenchmarkSettings );
			category.isEmpty = false;
		}
		settingsGroups = settingsGroup.GetGroups( m_isPreGame );
		for( i = 0; i < settingsGroups.Size(); i += 1 )
		{
			currentSettingsGroup = settingsGroups[ i ];
			if( currentSettingsGroup.IsEmpty( m_isPreGame || m_isBenchmarkSettings ) )
			{
				continue;
			}
			if( currentSettingsGroup.HasVars( m_isPreGame || m_isBenchmarkSettings ) )
			{
				currentSubcategory.label = currentSettingsGroup.GetDisplayName();
				currentSubcategory.options = currentSettingsGroup.GetVars( m_isPreGame || m_isBenchmarkSettings );
				currentSubcategory.isEmpty = false;
				category.subcategories.PushBack( currentSubcategory );
				category.isEmpty = false;
				m_settingsListener.Register( currentSettingsGroup.GetPath() );
			}
		}
		if( category.label == 'UI-Settings-KeyBindings' && !( IsKeyboardConnected() ) )
		{
			category.isEmpty = true;
		}
		if( ( m_isBenchmarkSettings && category.label != 'UI-Settings-Group-Graphics' ) && category.label != 'UI-Settings-Group-Video' )
		{
			category.isEmpty = true;
		}
		if( !( category.isEmpty ) )
		{
			m_data.PushBack( category );
			m_settingsListener.Register( settingsGroup.GetPath() );
		}
	}

	private function PopulateSettingsData()
	{
		var rootGroup : ConfigGroup;
		var allgroups : array< ConfigGroup >;
		var i : Int32;
		rootGroup = m_settings.GetRootGroup();
		allgroups = rootGroup.GetGroups( m_isPreGame );
		m_data.Clear();
		for( i = 0; i < allgroups.Size(); i += 1 )
		{
			AddSettingsGroup( allgroups[ i ] );
		}
		CheckDualSenseSettingsVisibility();
	}

	private function PopulateCategories( idx : Int32 )
	{
		var newData : ListItemData;
		var curCategoty : SettingsCategory;
		var i : Int32;
		m_selectorCtrl.Clear();
		for( i = 0; i < m_data.Size(); i += 1 )
		{
			curCategoty = m_data[ i ];
			if( !( curCategoty.isEmpty ) )
			{
				newData = new ListItemData;
				newData.label = GetLocalizedTextByKey( curCategoty.label );
				if( StrLen( newData.label ) == 0 )
				{
					newData.label = "<Not Localized> " + ( ( String )( curCategoty.label ) );
				}
				m_menusList.PushBack( curCategoty.groupPath );
				m_selectorCtrl.PushData( newData );
			}
		}
		m_selectorCtrl.Refresh();
		if( ( idx >= 0 ) && ( idx < m_data.Size() ) )
		{
			m_selectorCtrl.SetToggledIndex( idx );
		}
		else
		{
			m_selectorCtrl.SetToggledIndex( 0 );
		}
	}

	protected event OnSetMenuEventDispatcher( menuEventDispatcher : weak< inkMenuEventDispatcher > )
	{
		m_menuEventDispatcher = menuEventDispatcher;
		m_menuEventDispatcher.RegisterToEvent( 'OnBack', this, 'OnBack' );
	}

	protected event OnBack( userData : IScriptable )
	{
		if( !( StatusEffectSystem.ObjectHasStatusEffectWithTag( GetPlayerControlledObject(), 'LockInHubMenu' ) ) )
		{
			m_closeSettingsRequest = true;
			CheckSettings();
		}
	}

	private function RequestClose()
	{
		m_menuEventDispatcher.SpawnEvent( 'OnCloseSettingsScreen' );
		m_closeSettingsRequest = false;
	}

	private function RequestRestoreDefaults()
	{
		var groupPath : CName;
		var index : Int32;
		index = m_selectorCtrl.GetToggledIndex();
		groupPath = m_data[ index ].groupPath;
		m_settings.RequestRestoreDefaultDialog( m_isPreGame, false, groupPath );
	}

	private function CheckSettings()
	{
		if( m_resetSettingsRequest )
		{
			CheckRejectSettings();
		}
		else
		{
			CheckAcceptSettings();
		}
	}

	private function CheckRejectSettings()
	{
		if( m_settings.NeedsConfirmation() )
		{
			m_settings.RejectChanges();
		}
		else if( m_settings.NeedsRestartToApply() )
		{
			m_settings.RejectRestartToApply();
		}
		else if( m_settings.NeedsLoadLastCheckpoint() )
		{
			m_settings.RejectLoadLastCheckpointChanges();
		}
		else
		{
			m_resetSettingsRequest = false;
			if( m_closeSettingsRequest )
			{
				RequestClose();
			}
		}
	}

	private function CheckAcceptSettings()
	{
		if( m_settings.WasModifiedSinceLastSave() )
		{
			if( m_settings.NeedsConfirmation() )
			{
				if( IsBlockedByActionWithoutAssignedKey() )
				{
					m_settings.RequestRejectConfirmationDialog();
				}
				else
				{
					m_settings.RequestConfirmationDialog();
				}
			}
			else if( m_settings.NeedsRestartToApply() )
			{
				m_settings.RequestNeedsRestartDialog();
			}
			else if( m_settings.NeedsLoadLastCheckpoint() )
			{
				m_settings.RequestLoadLastCheckpointDialog();
			}
			else
			{
				GetSystemRequestsHandler().RequestSaveUserSettings();
				GameInstance.GetTelemetrySystem( GetPlayerControlledObject().GetGame() ).OnSettingsSave();
				if( m_closeSettingsRequest )
				{
					RequestClose();
				}
			}
		}
		else if( m_closeSettingsRequest )
		{
			RequestClose();
		}
	}

	private function SetSideButtonsVisiblity( i : Int32 )
	{
		inkWidgetRef.SetVisible( m_benchmarkButton, IsBenchmarkPossible() && ( m_menusList[ i ] == m_settingGroupName_Graphics || m_menusList[ i ] == m_settingGroupName_Video ) );
		inkWidgetRef.SetVisible( m_hdrButton, ( !( m_isBenchmarkSettings ) && m_showHdrButton ) && m_menusList[ i ] == m_settingGroupName_Video );
		inkWidgetRef.SetVisible( m_brightnessButton, ( !( m_isBenchmarkSettings ) && m_showBrightnessButton ) && m_menusList[ i ] == m_settingGroupName_Video );
		inkWidgetRef.SetVisible( m_controllerButton, m_menusList[ i ] == m_settingGroupName_Controls );
		inkWidgetRef.SetVisible( m_replayTutorialButton, m_menusList[ i ] == m_settingGroupName_Controls && !( GetSystemRequestsHandler().IsPreGame() ) );
		inkWidgetRef.SetVisible( m_safezonesButton, CanEditSafezones() && m_menusList[ i ] == m_settingGroupName_Interface );
		if( inkWidgetRef.IsVisible( m_replayTutorialButton ) )
		{
			EvaluateReplayTutorialButton();
		}
	}

	public function IsPlayerInCall( player : PlayerPuppet ) : Bool
	{
		var bbSystem : weak< BlackboardSystem >;
		var bbUiComDeviceDef : UI_ComDeviceDef;
		var bbUiComDevice : weak< IBlackboard >;
		var infoVariant : Variant;
		var lastPhoneCallInformation : PhoneCallInformation;
		bbSystem = GameInstance.GetBlackboardSystem( player.GetGame() );
		bbUiComDeviceDef = GetAllBlackboardDefs().UI_ComDevice;
		bbUiComDevice = bbSystem.Get( bbUiComDeviceDef );
		infoVariant = bbUiComDevice.GetVariant( bbUiComDeviceDef.PhoneCallInformation );
		if( infoVariant.IsValid() )
		{
			lastPhoneCallInformation = ( ( PhoneCallInformation )infoVariant );
			if( lastPhoneCallInformation.callPhase == questPhoneCallPhase.IncomingCall || lastPhoneCallInformation.callPhase == questPhoneCallPhase.StartCall )
			{
				return true;
			}
		}
		return false;
	}

	public function HasActiveWeaponGrenade( player : PlayerPuppet ) : Bool
	{
		var i : Int32;
		var projectileComponents : array< ProjectileComponent >;
		var projectileEntity : weak< Entity >;
		var activeWeaponGrenade : WeaponGrenade;
		projectileComponents = GameInstance.GetProjectileSystem( player.GetGame() ).GetRegisteredComponents();
		for( i = 0; i < projectileComponents.Size(); i += 1 )
		{
			projectileEntity = projectileComponents[ i ].GetEntity();
			if( !( projectileEntity ) )
			{
				continue;
			}
			activeWeaponGrenade = ( ( WeaponGrenade )( projectileEntity ) );
			if( activeWeaponGrenade )
			{
				return true;
			}
		}
		return false;
	}

	public function IsDangerousQuickhackActiveAroundPlayer( player : PlayerPuppet ) : Bool
	{
		var entities : array< Entity >;
		var target : VehicleObject;
		var i : Int32;
		var filter : TargetSearchFilter;
		filter = TSF_And( TSF_All( TSFMV.Obj_Device ), TSF_All( TSFMV.St_AliveAndActive ), TSF_All( TSFMV.Att_Neutral ) );
		entities = player.GetEntitiesAroundObject( 20.0, filter );
		for( i = 0; i < entities.Size(); i += 1 )
		{
			target = ( ( VehicleObject )( entities[ i ] ) );
			if( !( target ) )
			{
				continue;
			}
			if( target.IsVehicleAccelerateQuickhackActive() )
			{
				return true;
			}
		}
		return false;
	}

	public function EvaluateReplayTutorialButton()
	{
		var player : PlayerPuppet;
		var gameInstance : GameInstance;
		var questSystem : QuestsSystem;
		var questsContentSystem : QuestsContentSystem;
		var bboard : IBlackboard;
		var interactionChoiceHubData : InteractionChoiceHubData;
		var dialogChoiceHubs : DialogChoiceHubs;
		var noChoiceHubsShown : Bool;
		var upperBodyState : Int32;
		var locomotionState : Int32;
		var isLocomotionStateAllowed : Bool;
		var combatGadgetState : Int32;
		var leftHandCyberwareState : Int32;
		var isPlayerInsideElevator : Bool;
		var isPlayerInsideMovingElevator : Bool;
		var isOnGround : Bool;
		var uploadingQuickHackIDs : array< TweakDBID >;
		var isUploadingQuickhacks : Bool;
		var currentWantedLevel : Int32;
		player = ( ( PlayerPuppet )( GetPlayerControlledObject() ) );
		gameInstance = player.GetGame();
		questSystem = GameInstance.GetQuestsSystem( gameInstance );
		questsContentSystem = GameInstance.GetQuestsContentSystem( gameInstance );
		bboard = GameInstance.GetBlackboardSystem( gameInstance ).GetLocalInstanced( player.GetEntityID(), GetAllBlackboardDefs().PlayerStateMachine );
		upperBodyState = bboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.UpperBody );
		locomotionState = bboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.LocomotionDetailed );
		isLocomotionStateAllowed = ( ( ( ( Int32 )( gamePSMDetailedLocomotionStates.Stand ) ) == locomotionState ) || ( ( ( Int32 )( gamePSMDetailedLocomotionStates.AimWalk ) ) == locomotionState ) ) || ( ( ( Int32 )( gamePSMDetailedLocomotionStates.Sprint ) ) == locomotionState );
		combatGadgetState = bboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.CombatGadget );
		leftHandCyberwareState = bboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.LeftHandCyberware );
		isPlayerInsideElevator = bboard.GetBool( GetAllBlackboardDefs().PlayerStateMachine.IsPlayerInsideElevator );
		isPlayerInsideMovingElevator = bboard.GetBool( GetAllBlackboardDefs().PlayerStateMachine.IsPlayerInsideMovingElevator );
		isPlayerInsideElevator = isPlayerInsideElevator || isPlayerInsideMovingElevator;
		isOnGround = bboard.GetBool( GetAllBlackboardDefs().PlayerStateMachine.IsOnGround );
		uploadingQuickHackIDs = ( ( array< TweakDBID > )( bboard.GetVariant( GetAllBlackboardDefs().PlayerStateMachine.UploadingQuickHackIDs ) ) );
		isUploadingQuickhacks = uploadingQuickHackIDs.Size() > 0;
		bboard = GameInstance.GetBlackboardSystem( gameInstance ).Get( GetAllBlackboardDefs().UIInteractions );
		interactionChoiceHubData = ( ( InteractionChoiceHubData )( bboard.GetVariant( GetAllBlackboardDefs().UIInteractions.InteractionChoiceHub ) ) );
		dialogChoiceHubs = ( ( DialogChoiceHubs )( bboard.GetVariant( GetAllBlackboardDefs().UIInteractions.DialogChoiceHubs ) ) );
		noChoiceHubsShown = ( !( interactionChoiceHubData.active ) || ( interactionChoiceHubData.choices.Size() == 0 ) ) && ( dialogChoiceHubs.choiceHubs.Size() == 0 );
		bboard = GameInstance.GetBlackboardSystem( gameInstance ).Get( GetAllBlackboardDefs().UI_WantedBar );
		currentWantedLevel = bboard.GetInt( GetAllBlackboardDefs().UI_WantedBar.CurrentWantedLevel );
		if( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( !( player.IsInCombat() ) && !( player.IsReplacer() ) ) && ( PlayerPuppet.GetSceneTier( player ) == ( ( Int32 )( gamePSMHighLevel.SceneTier1 ) ) ) ) && !( PlayerPuppet.IsSwimming( player ) ) ) && !( VehicleComponent.IsMountedToVehicle( player.GetGame(), player ) ) ) && !( GameInstance.GetWorkspotSystem( player.GetGame() ).IsActorInWorkspot( player ) ) ) && ( ( ( Int32 )( gamePSMUpperBodyStates.TemporaryUnequip ) ) != upperBodyState ) ) && isLocomotionStateAllowed ) && ( ( ( Int32 )( gamePSMCombatGadget.Default ) ) == combatGadgetState ) ) && ( ( ( Int32 )( gamePSMLeftHandCyberware.Default ) ) == leftHandCyberwareState ) ) && ( questSystem.GetFact( 'replay_tutorial_quest_unlock' ) >= 1 ) ) && ( questSystem.GetFact( 'start_vr_tutorial_level' ) < 1 ) ) && ( questSystem.GetFact( 'disable_gyro_tutorials' ) < 1 ) ) && !( IsPlayerInCall( player ) ) ) && !( GetSystemRequestsHandler().IsPreGame() ) ) && !( isPlayerInsideElevator ) ) && isOnGround ) && !( isUploadingQuickhacks ) ) && noChoiceHubsShown ) && !( questsContentSystem.IsTokensActivationBlocked() ) ) && !( HasActiveWeaponGrenade( player ) ) ) && ( currentWantedLevel == 0 ) ) && !( StatusEffectSystem.ObjectHasStatusEffectWithTag( player, 'Tier2Locomotion' ) ) ) && !( StatusEffectSystem.ObjectHasStatusEffectWithTag( player, 'DoT' ) ) ) && !( IsDangerousQuickhackActiveAroundPlayer( player ) ) ) && !( GameInstance.GetTimeSystem( player.GetGame() ).IsTimeDilationActive() ) )
		{
			inkWidgetRef.SetState( m_replayTutorialButton, 'Default' );
			inkWidgetRef.SetInteractive( m_replayTutorialButton, true );
		}
		else
		{
			inkWidgetRef.SetState( m_replayTutorialButton, 'Disabled' );
			inkWidgetRef.SetInteractive( m_replayTutorialButton, false );
		}
	}

	public export function StartReplayTutorial()
	{
		( ( PlayerPuppet )( GetPlayerControlledObject() ) ).ApplyNoMovementStatGroupModifiers();
		m_menuEventDispatcher.SpawnEvent( 'OnClosePauseMenu' );
		GameInstance.GetQuestsSystem( GetPlayerControlledObject().GetGame() ).SetFact( 'start_vr_tutorial_level', 1 );
	}

	protected event OnMenuChanged( index : Int32, target : ListItemController )
	{
		PlaySound( 'Button', 'OnPress' );
		PopulateCategorySettingsOptions( index );
		( ( inkScrollController )( inkWidgetRef.GetController( m_scrollPanel ) ) ).SetScrollPosition( 0.0 );
		m_settings.SetMenuIndex( index );
		m_languageInstallProgressBar.SetEnabled( m_menusList[ index ] == m_settingGroupName_Language );
		SetLanguageDisclaimerVisiblity( index );
		CheckDualSenseSettingsVisibility();
		SetSideButtonsVisiblity( index );
		ForceResetCursorType();
	}

	protected event OnApplyButtonReleased( controller : weak< inkButtonController > )
	{
		m_closeSettingsRequest = false;
		OnApplyButton();
		CheckHDRSettingVisibility();
	}

	protected event OnResetButtonReleased( controller : weak< inkButtonController > )
	{
		m_closeSettingsRequest = false;
		OnResetButton();
	}

	protected event OnBrightnessButtonReleased( controller : weak< inkButtonController > )
	{
		ShowBrightnessScreen();
	}

	protected event OnHDRButtonReleased( controller : weak< inkButtonController > )
	{
		ShowHDRScreen();
	}

	protected event OnControllerButtonReleased( controller : weak< inkButtonController > )
	{
		ShowControllerScreen();
	}

	protected event OnPressReplayTutorial( evt : inkPointerEvent )
	{
		if( evt.IsAction( 'click' ) )
		{
			m_settings.RequestStartReplayTutorialDialog( this );
		}
	}

	protected event OnBenchmarkButtonReleased( controller : weak< inkButtonController > )
	{
		if( IsBenchmarkPossible() )
		{
			CheckSettings();
			RunGraphicsBenchmark();
		}
	}

	private function RunSafezonesEditor()
	{
		var data : inkGameNotificationData;
		data = new inkGameNotificationData;
		data.notificationName = 'base\gameplay\gui\fullscreen\settings\hud_safezones_editor.inkwidget';
		data.queueName = 'modal_popup_fullscreen';
		data.isBlocking = true;
		m_safezonesEditorToken = ShowGameNotification( data );
		m_safezonesEditorToken.RegisterListener( this, 'OnSafezonesEditorCloseRequest' );
	}

	protected event OnSafezonesButtonReleased( controller : weak< inkButtonController > )
	{
		if( CanEditSafezones() )
		{
			RunSafezonesEditor();
		}
	}

	protected event OnSafezonesEditorCloseRequest( data : inkGameNotificationData )
	{
		m_safezonesEditorToken = NULL;
	}

	protected event OnDefaultButtonReleased( controller : weak< inkButtonController > )
	{
		m_closeSettingsRequest = false;
		RequestRestoreDefaults();
	}

	protected event OnLocalizationChanged( evt : inkLocalizationChangedEvent )
	{
		var idx : Int32;
		idx = m_selectorCtrl.GetToggledIndex();
		PopulateCategories( idx );
		PopulateCategorySettingsOptions( idx );
		PopulateHints();
	}

	private function PopulateHints()
	{
		m_buttonHintsController.ClearButtonHints();
		m_buttonHintsController.AddButtonHint( 'back', "Common-Access-Close" );
		if( !( m_isDlcSettings ) )
		{
			m_buttonHintsController.AddButtonHint( 'restore_default_settings', "UI-UserActions-RestoreDefaults" );
		}
	}

	private function OnApplyButton()
	{
		if( IsBlockedByActionWithoutAssignedKey() )
		{
			PushNotification( 'UI-Labels-Settings', 'UI-Settings-Video-keybindingerror' );
			return;
		}
		if( !( IsApplyButtonEnabled() ) )
		{
			return;
		}
		if( m_settings.NeedsConfirmation() )
		{
			m_settings.ConfirmChanges();
		}
		else
		{
			CheckSettings();
		}
	}

	private function OnResetButton()
	{
		if( !( IsResetButtonEnabled() ) )
		{
			return;
		}
		m_resetSettingsRequest = true;
		CheckSettings();
	}

	private function ShowBrightnessScreen()
	{
		m_menuEventDispatcher.SpawnEvent( 'OnSwitchToBrightnessSettings' );
	}

	private function ShowHDRScreen()
	{
		m_menuEventDispatcher.SpawnEvent( 'OnSwitchToHDRSettings' );
	}

	private function ShowControllerScreen()
	{
		m_menuEventDispatcher.SpawnEvent( 'OnSwitchToControllerPanel' );
	}

	private function IsBlockedByActionWithoutAssignedKey() : Bool
	{
		var i : Int32;
		for( i = 0; i < m_data.Size(); i += 1 )
		{
			if( !( m_data[ i ].isEmpty ) && m_data[ i ].groupPath == m_settingGroupName_KeyBindings )
			{
				return IsAnyActionWithoutAssignedKey();
			}
		}
		return false;
	}

	protected event OnButtonRelease( evt : inkPointerEvent )
	{
		var currentToggledIndex : Int32;
		var listSize : Int32;
		CheckDualSenseSettingsVisibility();
		listSize = m_selectorCtrl.Size();
		if( evt.IsAction( 'prior_menu' ) )
		{
			currentToggledIndex = m_selectorCtrl.GetToggledIndex();
			if( currentToggledIndex < 1 )
			{
				m_selectorCtrl.SetToggledIndex( listSize - 1 );
			}
			else
			{
				m_selectorCtrl.SetToggledIndex( currentToggledIndex - 1 );
			}
		}
		else if( evt.IsAction( 'next_menu' ) )
		{
			currentToggledIndex = m_selectorCtrl.GetToggledIndex();
			if( currentToggledIndex >= ( m_selectorCtrl.Size() - 1 ) )
			{
				m_selectorCtrl.SetToggledIndex( 0 );
			}
			else
			{
				m_selectorCtrl.SetToggledIndex( currentToggledIndex + 1 );
			}
		}
		else if( evt.IsAction( 'brightness_settings' ) && m_menusList[ m_settings.GetMenuIndex() ] == m_settingGroupName_Video )
		{
			if( inkWidgetRef.IsVisible( m_resetButton ) )
			{
				OnResetButton();
			}
			if( m_showHdrButton )
			{
				ShowHDRScreen();
			}
			if( inkWidgetRef.IsVisible( m_brightnessButton ) )
			{
				ShowBrightnessScreen();
			}
		}
		else if( evt.IsAction( 'controller_settings' ) && inkWidgetRef.IsVisible( m_controllerButton ) )
		{
			ShowControllerScreen();
		}
		else if( evt.IsAction( 'restore_default_settings' ) )
		{
			RequestRestoreDefaults();
		}
		else if( ( evt.IsAction( 'run_benchmark' ) && IsBenchmarkPossible() ) && inkWidgetRef.IsVisible( m_benchmarkButton ) )
		{
			RunGraphicsBenchmark();
		}
		else if( evt.IsAction( 'edit_safezones' ) )
		{
			if( CanEditSafezones() && inkWidgetRef.IsVisible( m_safezonesButton ) )
			{
				RunSafezonesEditor();
			}
			if( inkWidgetRef.IsVisible( m_replayTutorialButton ) && inkWidgetRef.IsInteractive( m_replayTutorialButton ) )
			{
				m_settings.RequestStartReplayTutorialDialog( this );
			}
		}
		else
		{
			return false;
		}
	}

	protected event OnSettingHoverOver( evt : inkPointerEvent )
	{
		var currentItem : weak< SettingsSelectorController >;
		var updatePolicy : ConfigVarUpdatePolicy;
		var description : String;
		currentItem = ( ( SettingsSelectorController )( evt.GetCurrentTarget().GetController() ) );
		if( currentItem )
		{
			updatePolicy = currentItem.GetVarUpdatePolicy();
			description = GetLocalizedTextByKey( currentItem.GetDescription() );
			if( currentItem.GetWarning() != 'None' )
			{
				description += "\n\n";
				description += GetLocalizedTextByKey( currentItem.GetWarning() );
			}
			if( updatePolicy == ConfigVarUpdatePolicy.ConfirmationRequired )
			{
				description += "\n\n";
				description += GetLocalizedText( "LocKey#76947" );
			}
			else if( updatePolicy == ConfigVarUpdatePolicy.RestartRequired )
			{
				description += "\n\n";
				description += ( ( "<Rich " + m_descriptionWarningRichColor ) + ">" );
				description += GetLocalizedText( "LocKey#76948" );
				description += "</>";
			}
			inkTextRef.SetText( m_descriptionText, description );
			inkTextRef.SetVisible( m_descriptionText, true );
		}
	}

	protected event OnSettingHoverOut( evt : inkPointerEvent )
	{
		inkTextRef.SetVisible( m_descriptionText, false );
	}

	private function PopulateOptions( const options : ref< array< ConfigVar > > )
	{
		var i : Int32;
		var size : Int32;
		var currentSettingsItem : ConfigVar;
		var currentSettingsGroup : ConfigGroup;
		var currentSettingsItemType : ConfigVarType;
		var currentItem : weak< SettingsSelectorController >;
		var currentVoItem : weak< SettingsSelectorControllerLanguagesList >;
		var isVoiceOver : Bool;
		var isKeyBinding : Bool;
		size = options.Size();
		for( i = 0; i < size; i += 1 )
		{
			currentSettingsItem = options[ i ];
			if( !( currentSettingsItem ) )
			{
				continue;
			}
			if( !( currentSettingsItem.IsVisible() ) )
			{
				continue;
			}
			currentSettingsItemType = currentSettingsItem.GetType();
			currentSettingsGroup = currentSettingsItem.GetGroup();
			isVoiceOver = currentSettingsItem.GetName() == 'VoiceOver';
			isKeyBinding = currentSettingsGroup.GetParentPath() == m_settingGroupName_KeyBindings;
			switch( currentSettingsItemType )
			{
				case ConfigVarType.Bool:
					currentItem = ( ( SettingsSelectorController )( SpawnFromLocal( inkCompoundRef.Get( m_settingsOptionsList ), 'settingsSelectorBool' ).GetController() ) );
				break;
				case ConfigVarType.Int:
					currentItem = ( ( SettingsSelectorController )( SpawnFromLocal( inkCompoundRef.Get( m_settingsOptionsList ), 'settingsSelectorInt' ).GetController() ) );
				break;
				case ConfigVarType.Float:
					currentItem = ( ( SettingsSelectorController )( SpawnFromLocal( inkCompoundRef.Get( m_settingsOptionsList ), 'settingsSelectorFloat' ).GetController() ) );
				break;
				case ConfigVarType.Name:
					if( isKeyBinding )
					{
						currentItem = ( ( SettingsSelectorController )( SpawnFromLocal( inkCompoundRef.Get( m_settingsOptionsList ), 'settingsSelectorKeyBinding' ).GetController() ) );
					}
				break;
				case ConfigVarType.IntList:
					currentItem = ( ( SettingsSelectorController )( SpawnFromLocal( inkCompoundRef.Get( m_settingsOptionsList ), 'settingsSelectorIntList' ).GetController() ) );
				break;
				case ConfigVarType.FloatList:
					currentItem = ( ( SettingsSelectorController )( SpawnFromLocal( inkCompoundRef.Get( m_settingsOptionsList ), 'settingsSelectorFloatList' ).GetController() ) );
				break;
				case ConfigVarType.StringList:
					currentItem = ( ( SettingsSelectorController )( SpawnFromLocal( inkCompoundRef.Get( m_settingsOptionsList ), 'settingsSelectorStringList' ).GetController() ) );
				break;
				case ConfigVarType.NameList:
					if( !( isVoiceOver ) )
					{
						currentItem = ( ( SettingsSelectorController )( SpawnFromLocal( inkCompoundRef.Get( m_settingsOptionsList ), 'settingsSelectorNameList' ).GetController() ) );
					}
					else
					{
						currentItem = ( ( SettingsSelectorController )( SpawnFromLocal( inkCompoundRef.Get( m_settingsOptionsList ), 'settingsSelectorLanguagesList' ).GetController() ) );
					}
				break;
				default:
					break;
			}
			if( currentItem )
			{
				currentItem.Setup( currentSettingsItem, m_isPreGame || m_isBenchmarkSettings );
				currentItem.RegisterToCallback( 'OnHoverOver', this, 'OnSettingHoverOver' );
				currentItem.RegisterToCallback( 'OnHoverOut', this, 'OnSettingHoverOut' );
				if( currentSettingsItem.IsDisabled() )
				{
					currentItem.GetRootWidget().SetState( 'Disabled' );
					currentItem.SetInteractive( false );
				}
				if( currentSettingsItem.IsSubOption() )
				{
					currentItem.AddLabelIndent( m_useRightAligned );
				}
				if( isVoiceOver )
				{
					currentVoItem = ( ( SettingsSelectorControllerLanguagesList )( currentItem ) );
					currentVoItem.RegisterDownloadButtonHovers( m_descriptionText );
				}
				m_settingsElements.PushBack( currentItem );
			}
		}
	}

	private function PopulateCategorySettingsOptions( idx : Int32 )
	{
		var i : Int32;
		var settingsCategory : SettingsCategory;
		var settingsSubCategory : SettingsCategory;
		var categoryController : SettingsCategoryController;
		m_settingsElements.Clear();
		inkCompoundRef.RemoveAllChildren( m_settingsOptionsList );
		inkTextRef.SetText( m_descriptionText, "" );
		inkTextRef.SetVisible( m_descriptionText, false );
		if( idx < 0 )
		{
			idx = m_selectorCtrl.GetToggledIndex();
		}
		settingsCategory = m_data[ idx ];
		PopulateOptions( settingsCategory.options );
		for( i = 0; i < settingsCategory.subcategories.Size(); i += 1 )
		{
			settingsSubCategory = settingsCategory.subcategories[ i ];
			categoryController = ( ( SettingsCategoryController )( SpawnFromLocal( inkCompoundRef.Get( m_settingsOptionsList ), 'settingsCategory' ).GetController() ) );
			if( categoryController )
			{
				categoryController.Setup( settingsSubCategory.label );
			}
			PopulateOptions( settingsSubCategory.options );
		}
		m_selectorCtrl.SetSelectedIndex( idx );
	}

}

class SettingsLanguageInstallProgressBar extends inkLogicController
{
	private editable var progressBarRoot : inkWidgetRef;
	private editable var progressBarFill : inkWidgetRef;
	private editable var textProgress : inkTextRef;
	private var m_isEnabled : Bool;

	protected event OnInitialize()
	{
		SetProgressBarVisiblity( false, true );
	}

	public function SetEnabled( isEnabled : Bool )
	{
		m_isEnabled = isEnabled;
		if( !( m_isEnabled ) )
		{
			inkWidgetRef.SetVisible( progressBarRoot, false );
		}
	}

	public function SetProgressBarVisiblity( visible : Bool, optional force : Bool )
	{
		if( m_isEnabled || force )
		{
			inkWidgetRef.SetVisible( progressBarRoot, visible );
		}
	}

	public function SetProgress( progress : Float )
	{
		var scale : Vector2;
		var formatParams : inkTextParams;
		var valueInt : Int32;
		scale = inkWidgetRef.GetScale( progressBarFill );
		scale.X = progress;
		inkWidgetRef.SetScale( progressBarFill, scale );
		valueInt = ( ( Int32 )( progress * 100.0 ) );
		formatParams = new inkTextParams;
		formatParams.AddNumber( "VALUE", valueInt );
		inkTextRef.SetText( textProgress, "{VALUE} %", formatParams );
	}

}

