class HoverEvent extends Event
{
	var hooverOn : Bool;
}

import class KeyBindingEvent extends Event
{
	import var keyName : CName;
}

import class SettingsSelectorController extends inkLogicController
{
	protected editable var m_LabelText : inkTextRef;
	protected editable var m_ModifiedFlag : inkTextRef;
	protected editable var m_Raycaster : inkWidgetRef;
	protected editable var m_optionSwitchHint : inkWidgetRef;
	protected editable var m_hoverGeneralHighlight : inkWidgetRef;
	protected editable var m_container : inkWidgetRef;
	protected editable var m_indentMarker : inkWidgetRef;
	protected var m_SettingsEntry : weak< ConfigVar >;
	protected var m_hoveredChildren : array< weak< inkWidget > >;
	protected var m_IsPreGame : Bool;
	private var m_varGroupPath : CName;
	private var m_varName : CName;
	protected var m_additionalText : CName;

	public import function BindSettings( entry : ConfigVar );
	public import function GetDisplayName() : CName;
	public import function GetDescription() : CName;

	private var m_hoverInAnim : inkAnimProxy;
	private var m_hoverOutAnim : inkAnimProxy;

	public function GetVar() : weak< ConfigVar >
	{
		return m_SettingsEntry;
	}

	public function GetGroupPath() : CName
	{
		return m_varGroupPath;
	}

	public function GetVarName() : CName
	{
		return m_varName;
	}

	public function GetVarUpdatePolicy() : ConfigVarUpdatePolicy
	{
		return m_SettingsEntry.GetUpdatePolicy();
	}

	public function IsDynamic() : Bool
	{
		return m_SettingsEntry.IsDynamic();
	}

	public function SetAdditionalText( text : CName )
	{
		m_additionalText = text;
	}

	public function ResetAdditionalText()
	{
		m_additionalText = '';
	}

	public virtual function SetInteractive( interactive : Bool ) {}

	public virtual function Setup( entry : ConfigVar, isPreGame : Bool )
	{
		m_SettingsEntry = entry;
		m_IsPreGame = isPreGame;
		m_varGroupPath = m_SettingsEntry.GetGroupPath();
		m_varName = m_SettingsEntry.GetName();
		BindSettings( entry );
	}

	protected event OnInitialize()
	{
		if( inkWidgetRef.IsValid( m_Raycaster ) )
		{
			inkWidgetRef.SetVisible( m_optionSwitchHint, false );
			inkWidgetRef.SetVisible( m_hoverGeneralHighlight, false );
			inkTextRef.SetState( m_LabelText, 'Default' );
			RegisterToCallback( 'OnHoverOver', this, 'OnHoverOver' );
			RegisterToCallback( 'OnHoverOut', this, 'OnHoverOut' );
		}
		inkWidgetRef.SetVisible( m_indentMarker, false );
	}

	protected event OnHoverOver( e : inkPointerEvent )
	{
		if( m_SettingsEntry.IsDisabled() )
		{
			return false;
		}
		if( m_hoveredChildren.Size() <= 0 )
		{
			if( m_hoverInAnim.IsPlaying() )
			{
				m_hoverInAnim.Stop();
			}
			if( m_hoverOutAnim.IsPlaying() )
			{
				m_hoverOutAnim.Stop();
			}
			m_hoverInAnim = PlayLibraryAnimation( 'hover_over_anim' );
			inkTextRef.SetState( m_LabelText, 'Hover' );
			inkWidgetRef.SetVisible( m_optionSwitchHint, true );
			inkWidgetRef.SetVisible( m_hoverGeneralHighlight, true );
		}
		m_hoveredChildren.PushBack( e.GetCurrentTarget() );
	}

	protected event OnHoverOut( e : inkPointerEvent )
	{
		if( m_SettingsEntry.IsDisabled() )
		{
			return false;
		}
		m_hoveredChildren.Remove( e.GetCurrentTarget() );
		if( m_hoveredChildren.Size() <= 0 )
		{
			if( m_hoverInAnim.IsPlaying() )
			{
				m_hoverInAnim.Stop();
			}
			if( m_hoverOutAnim.IsPlaying() )
			{
				m_hoverOutAnim.Stop();
			}
			m_hoverOutAnim = PlayLibraryAnimation( 'hover_out_anim' );
			inkTextRef.SetState( m_LabelText, 'Default' );
			inkWidgetRef.SetVisible( m_optionSwitchHint, false );
			inkWidgetRef.SetVisible( m_hoverGeneralHighlight, false );
		}
	}

	protected event OnElementHovered( e : inkPointerEvent )
	{
		CallCustomCallback( 'OnSettingHovered' );
	}

	protected event OnUpdateValue()
	{
		Refresh();
	}

	public virtual function Refresh()
	{
		var text : String;
		var languageProvider : inkLanguageOverrideProvider;
		var updatePolicy : ConfigVarUpdatePolicy;
		var wasModified : Bool;
		var modifiedSymbol : String;
		var i, size : Int32;
		size = m_SettingsEntry.GetDisplayNameKeysSize();
		if( size > 0 )
		{
			text = NameToString( m_SettingsEntry.GetDisplayName() );
			for( i = 0; i < size; i += 1 )
			{
				text = StrReplace( text, "%", GetLocalizedTextByKey( m_SettingsEntry.GetDisplayNameKey( i ) ) );
			}
		}
		else
		{
			text = GetLocalizedTextByKey( m_SettingsEntry.GetDisplayName() );
		}
		updatePolicy = m_SettingsEntry.GetUpdatePolicy();
		if( text == "" )
		{
			text = "<NOT LOCALIZED>" + NameToString( m_SettingsEntry.GetDisplayName() );
		}
		if( updatePolicy == ConfigVarUpdatePolicy.ConfirmationRequired )
		{
			modifiedSymbol = "*";
			wasModified = m_SettingsEntry.HasRequestedValue();
		}
		else if( updatePolicy == ConfigVarUpdatePolicy.RestartRequired || updatePolicy == ConfigVarUpdatePolicy.LoadLastCheckpointRequired )
		{
			modifiedSymbol = "!";
			wasModified = m_SettingsEntry.HasRequestedValue() || m_SettingsEntry.WasModifiedSinceLastSave();
		}
		else
		{
			modifiedSymbol = "";
			wasModified = false;
		}
		languageProvider = ( ( inkLanguageOverrideProvider )( inkTextRef.GetUserData( m_LabelText, 'inkLanguageOverrideProvider' ) ) );
		languageProvider.SetLanguage( scnDialogLineLanguage.Origin );
		inkTextRef.UpdateLanguageResources( m_LabelText, false );
		inkTextRef.SetText( m_LabelText, text );
		inkTextRef.SetVisible( m_ModifiedFlag, wasModified );
		inkTextRef.SetText( m_ModifiedFlag, modifiedSymbol );
	}

	public function AddLabelIndent( optional isRightAligned : Bool )
	{
		inkWidgetRef.SetVisible( m_indentMarker, true );
		if( isRightAligned )
		{
			inkTextRef.UpdateMargin( m_LabelText, 0.0, 0.0, 100.0, 0.0 );
		}
		else
		{
			inkTextRef.UpdateMargin( m_LabelText, 100.0, 0.0, 0.0, 0.0 );
		}
	}

	protected event OnLeft( e : inkPointerEvent )
	{
		if( !( m_SettingsEntry.IsDisabled() ) && e.IsAction( 'click' ) )
		{
			AcceptValue( false );
			PlaySound( 'ButtonValueDown', 'OnPress' );
		}
	}

	protected event OnRight( e : inkPointerEvent )
	{
		if( !( m_SettingsEntry.IsDisabled() ) && e.IsAction( 'click' ) )
		{
			AcceptValue( true );
			PlaySound( 'ButtonValueUp', 'OnPress' );
		}
	}

	protected event OnShortcutRepeat( e : inkPointerEvent )
	{
		if( !( m_SettingsEntry.IsDisabled() ) && !( e.IsHandled() ) )
		{
			if( e.IsAction( 'option_switch_prev_settings' ) )
			{
				ChangeValue( false );
				e.Handle();
			}
			else if( e.IsAction( 'option_switch_next_settings' ) )
			{
				ChangeValue( true );
				e.Handle();
			}
		}
	}

	protected event OnShortcutPress( e : inkPointerEvent )
	{
		if( !( m_SettingsEntry.IsDisabled() ) && !( e.IsHandled() ) )
		{
			if( e.IsAction( 'option_switch_prev_settings' ) )
			{
				PlaySound( 'ButtonValueDown', 'OnPress' );
				AcceptValue( false );
				e.Handle();
			}
			else if( e.IsAction( 'option_switch_next_settings' ) )
			{
				PlaySound( 'ButtonValueUp', 'OnPress' );
				AcceptValue( true );
				e.Handle();
			}
		}
	}

	private virtual function AcceptValue( forward : Bool )
	{
		ChangeValue( forward );
	}

	private virtual function ChangeValue( forward : Bool ) {}
}

class SettingsSelectorControllerBool extends SettingsSelectorController
{
	protected editable var m_onState : inkWidgetRef;
	protected editable var m_offState : inkWidgetRef;
	protected editable var m_onStateBody : inkWidgetRef;
	protected editable var m_offStateBody : inkWidgetRef;

	public override function Setup( entry : ConfigVar, isPreGame : Bool )
	{
		super.Setup( entry, isPreGame );
	}

	public override function Refresh()
	{
		var buttonLogic : inkButtonController;
		var realValue : ConfigVarBool;
		var value : Bool;
		realValue = ( ( ConfigVarBool )( m_SettingsEntry ) );
		super.Refresh();
		value = realValue.GetValue();
		inkWidgetRef.SetVisible( m_onState, value );
		inkWidgetRef.SetVisible( m_offState, !( value ) );
		buttonLogic = ( ( inkButtonController )( inkWidgetRef.GetControllerByType( m_onState, 'inkButtonController' ) ) );
		if( buttonLogic )
		{
			buttonLogic.SetEnabled( !( m_SettingsEntry.IsDisabled() ) );
		}
		buttonLogic = ( ( inkButtonController )( inkWidgetRef.GetControllerByType( m_offState, 'inkButtonController' ) ) );
		if( buttonLogic )
		{
			buttonLogic.SetEnabled( !( m_SettingsEntry.IsDisabled() ) );
		}
	}

	public override function SetInteractive( interactive : Bool )
	{
		inkWidgetRef.SetInteractive( m_onStateBody, interactive );
		inkWidgetRef.SetInteractive( m_offStateBody, interactive );
	}

	protected event OnInitialize()
	{
		super.OnInitialize();
		if( inkWidgetRef.IsValid( m_offStateBody ) )
		{
			inkWidgetRef.RegisterToCallback( m_offStateBody, 'OnRelease', this, 'OnLeft' );
		}
		if( inkWidgetRef.IsValid( m_onStateBody ) )
		{
			inkWidgetRef.RegisterToCallback( m_onStateBody, 'OnRelease', this, 'OnRight' );
		}
		if( inkWidgetRef.IsValid( m_Raycaster ) )
		{
			RegisterToCallback( 'OnRelease', this, 'OnShortcutPress' );
		}
	}

	private override function AcceptValue( forward : Bool )
	{
		var boolValue : ConfigVarBool;
		boolValue = ( ( ConfigVarBool )( m_SettingsEntry ) );
		boolValue.Toggle();
	}

}

import class SettingsSelectorControllerKeyBinding extends SettingsSelectorController
{
	private editable var m_text : inkRichTextBoxRef;
	private editable var m_buttonRef : inkWidgetRef;
	private editable var m_editView : inkWidgetRef;
	private editable var m_editOpacity : Float;
	default m_editOpacity = 0.4f;

	public import function IsListeningForInput() : Bool;
	public import function ListenForInput();
	public import function StopListeningForInput();
	public import function TriggerActionFeedback();
	public import static function PrepareInputTag( keyName, groupName, actionName : CName ) : String;

	protected event OnInitialize()
	{
		super.OnInitialize();
		if( inkWidgetRef.IsValid( m_buttonRef ) )
		{
			inkWidgetRef.RegisterToCallback( m_buttonRef, 'OnRelease', this, 'OnRelease' );
		}
	}

	protected event OnUninitialize()
	{
		if( inkWidgetRef.IsValid( m_buttonRef ) )
		{
			inkWidgetRef.UnregisterFromCallback( m_buttonRef, 'OnRelease', this, 'OnRelease' );
		}
	}

	private function IsCancel( keyName : CName ) : Bool
	{
		return keyName == 'IK_Escape';
	}

	protected event OnKeyBindingEvent( e : KeyBindingEvent )
	{
		if( IsListeningForInput() )
		{
			if( !( IsCancel( e.keyName ) ) )
			{
				SetValue( e.keyName );
			}
			else
			{
				Refresh();
			}
			StopListeningForInput();
			inkWidgetRef.SetOpacity( m_editView, 0.0 );
		}
	}

	public override function Refresh()
	{
		var varName : ConfigVarName;
		super.Refresh();
		varName = ( ( ConfigVarName )( m_SettingsEntry ) );
		inkRichTextBoxRef.SetText( m_text, PrepareInputTag( varName.GetValue(), varName.GetGroup().GetName(), varName.GetName() ) );
		TriggerActionFeedback();
	}

	protected event OnRelease( e : inkPointerEvent )
	{
		if( e.IsAction( 'click' ) )
		{
			inkRichTextBoxRef.SetLocalizedText( m_text, 'UI-Settings-ButtonMappings-Misc-KeyBind' );
			inkWidgetRef.SetOpacity( m_editView, m_editOpacity );
			ListenForInput();
		}
		else if( e.IsAction( 'unequip_item' ) )
		{
			ResetValue();
		}
	}

	private function SetValue( key : CName )
	{
		var value : ConfigVarName;
		value = ( ( ConfigVarName )( m_SettingsEntry ) );
		value.SetValue( key );
	}

	private function ResetValue()
	{
		GetVar().RestoreDefault();
	}

}

class SettingsSelectorControllerRange extends SettingsSelectorController
{
	protected editable var m_ValueText : inkTextRef;
	protected editable var m_LeftArrow : inkWidgetRef;
	protected editable var m_RightArrow : inkWidgetRef;
	protected editable var m_ProgressBar : inkWidgetRef;

	protected event OnInitialize()
	{
		super.OnInitialize();
		if( inkWidgetRef.IsValid( m_LeftArrow ) )
		{
			inkWidgetRef.RegisterToCallback( m_LeftArrow, 'OnRelease', this, 'OnLeft' );
		}
		if( inkWidgetRef.IsValid( m_RightArrow ) )
		{
			inkWidgetRef.RegisterToCallback( m_RightArrow, 'OnRelease', this, 'OnRight' );
		}
		if( inkWidgetRef.IsValid( m_Raycaster ) )
		{
			RegisterShortcutCallbacks();
		}
	}

	public override function Refresh()
	{
		var buttonLogic : inkButtonController;
		super.Refresh();
		if( inkWidgetRef.IsValid( m_RightArrow ) )
		{
			inkWidgetRef.SetVisible( m_RightArrow, !( m_SettingsEntry.IsDisabled() ) );
		}
		if( inkWidgetRef.IsValid( m_LeftArrow ) )
		{
			inkWidgetRef.SetVisible( m_LeftArrow, !( m_SettingsEntry.IsDisabled() ) );
		}
		if( inkWidgetRef.IsValid( m_container ) )
		{
			buttonLogic = ( ( inkButtonController )( inkWidgetRef.GetControllerByType( m_container, 'inkButtonController' ) ) );
			if( buttonLogic )
			{
				buttonLogic.SetEnabled( !( m_SettingsEntry.IsDisabled() ) );
			}
		}
	}

	protected virtual function RegisterShortcutCallbacks()
	{
		RegisterToCallback( 'OnRelease', this, 'OnShortcutPress' );
	}

	protected function UpdateValueTextLanguageResources()
	{
		var languageProvider : inkLanguageOverrideProvider;
		languageProvider = ( ( inkLanguageOverrideProvider )( inkTextRef.GetUserData( m_ValueText, 'inkLanguageOverrideProvider' ) ) );
		languageProvider.SetLanguage( scnDialogLineLanguage.Origin );
		inkTextRef.UpdateLanguageResources( m_ValueText, false );
	}

}

class SettingsSelectorControllerInt extends SettingsSelectorControllerRange
{
	private var m_newValue : Int32;
	private editable var m_sliderWidget : inkWidgetRef;
	private var m_sliderController : weak< inkSliderController >;

	public override function Setup( entry : ConfigVar, isPreGame : Bool )
	{
		var value : ConfigVarInt;
		super.Setup( entry, isPreGame );
		value = ( ( ConfigVarInt )( m_SettingsEntry ) );
		m_sliderController = ( ( inkSliderController )( inkWidgetRef.GetControllerByType( m_sliderWidget, 'inkSliderController' ) ) );
		m_sliderController.Setup( ( ( Float )( value.GetMinValue() ) ), ( ( Float )( value.GetMaxValue() ) ), ( ( Float )( m_newValue ) ), ( ( Float )( value.GetStepValue() ) ) );
		m_sliderController.RegisterToCallback( 'OnSliderValueChanged', this, 'OnSliderValueChanged' );
		m_sliderController.RegisterToCallback( 'OnSliderHandleReleased', this, 'OnHandleReleased' );
	}

	protected event OnSliderValueChanged( sliderController : weak< inkSliderController >, progress, value : Float )
	{
		m_newValue = ( ( Int32 )( ClampF( value, m_sliderController.GetMinValue(), m_sliderController.GetMaxValue() ) ) );
		Refresh();
	}

	protected event OnHandleReleased()
	{
		var value : ConfigVarInt;
		value = ( ( ConfigVarInt )( m_SettingsEntry ) );
		value.SetValue( m_newValue );
	}

	private override function RegisterShortcutCallbacks()
	{
		super.RegisterShortcutCallbacks();
		RegisterToCallback( 'OnRepeat', this, 'OnShortcutRepeat' );
	}

	private override function ChangeValue( forward : Bool )
	{
		var step : Int32;
		var value : ConfigVarInt;
		value = ( ( ConfigVarInt )( m_SettingsEntry ) );
		step = ( ( forward ) ? ( value.GetStepValue() ) : ( -( value.GetStepValue() ) ) );
		m_newValue = Clamp( m_newValue + step, value.GetMinValue(), value.GetMaxValue() );
		Refresh();
	}

	private override function AcceptValue( forward : Bool )
	{
		var value : ConfigVarInt;
		value = ( ( ConfigVarInt )( m_SettingsEntry ) );
		if( value.GetValue() == m_newValue )
		{
			ChangeValue( forward );
		}
		value.SetValue( m_newValue );
	}

	public override function Refresh()
	{
		super.Refresh();
		UpdateValueTextLanguageResources();
		inkTextRef.SetText( m_ValueText, IntToString( m_newValue ) );
		m_sliderController.ChangeValue( ( ( Float )( m_newValue ) ) );
	}

	protected event OnUpdateValue()
	{
		var value : ConfigVarInt;
		value = ( ( ConfigVarInt )( m_SettingsEntry ) );
		m_newValue = value.GetValue();
		super.OnUpdateValue();
	}

}

class SettingsSelectorControllerFloat extends SettingsSelectorControllerRange
{
	var m_newValue : Float;
	private editable var m_sliderWidget : inkWidgetRef;
	private var m_sliderController : weak< inkSliderController >;

	public override function Setup( entry : ConfigVar, isPreGame : Bool )
	{
		var value : ConfigVarFloat;
		super.Setup( entry, isPreGame );
		value = ( ( ConfigVarFloat )( m_SettingsEntry ) );
		m_sliderController = ( ( inkSliderController )( inkWidgetRef.GetControllerByType( m_sliderWidget, 'inkSliderController' ) ) );
		m_sliderController.Setup( value.GetMinValue(), value.GetMaxValue(), m_newValue, value.GetStepValue() );
		m_sliderController.RegisterToCallback( 'OnSliderValueChanged', this, 'OnSliderValueChanged' );
		m_sliderController.RegisterToCallback( 'OnSliderHandleReleased', this, 'OnHandleReleased' );
	}

	protected event OnSliderValueChanged( sliderController : weak< inkSliderController >, progress, value : Float )
	{
		m_newValue = ClampF( value, m_sliderController.GetMinValue(), m_sliderController.GetMaxValue() );
		Refresh();
	}

	protected event OnHandleReleased()
	{
		var value : ConfigVarFloat;
		value = ( ( ConfigVarFloat )( m_SettingsEntry ) );
		value.SetValue( m_newValue );
	}

	private override function RegisterShortcutCallbacks()
	{
		super.RegisterShortcutCallbacks();
		RegisterToCallback( 'OnRepeat', this, 'OnShortcutRepeat' );
	}

	private override function ChangeValue( forward : Bool )
	{
		var step : Float;
		var value : ConfigVarFloat;
		value = ( ( ConfigVarFloat )( m_SettingsEntry ) );
		step = ( ( forward ) ? ( value.GetStepValue() ) : ( -( value.GetStepValue() ) ) );
		m_newValue = ClampF( m_newValue + step, value.GetMinValue(), value.GetMaxValue() );
		Refresh();
	}

	private override function AcceptValue( forward : Bool )
	{
		var value : ConfigVarFloat;
		value = ( ( ConfigVarFloat )( m_SettingsEntry ) );
		if( value.GetValue() == m_newValue )
		{
			ChangeValue( forward );
		}
		value.SetValue( m_newValue );
	}

	public override function Refresh()
	{
		super.Refresh();
		UpdateValueTextLanguageResources();
		inkTextRef.SetText( m_ValueText, FloatToStringPrec( m_newValue, 2 ) );
		m_sliderController.ChangeValue( m_newValue );
	}

	protected event OnUpdateValue()
	{
		var value : ConfigVarFloat;
		value = ( ( ConfigVarFloat )( m_SettingsEntry ) );
		m_newValue = value.GetValue();
		super.OnUpdateValue();
	}

}

class SettingsSelectorControllerList extends SettingsSelectorControllerRange
{
	protected editable var m_dotsContainer : inkHorizontalPanelRef;

	protected function PopulateDots( size : Int32 )
	{
		var i : Int32;
		var parentSize : Vector2;
		var parentWidth : Float;
		var dotWidth : Float;
		var dot : weak< inkWidget >;
		inkHorizontalPanelRef.RemoveAllChildren( m_dotsContainer );
		parentSize = inkHorizontalPanelRef.GetSize( m_dotsContainer );
		parentWidth = parentSize.X;
		dotWidth = ( parentWidth / ( ( Float )( size ) ) ) - 8.0;
		dotWidth = ClampF( dotWidth, 8.0, 40.0 );
		for( i = 0; i < size; i += 1 )
		{
			dot = SpawnFromLocal( inkHorizontalPanelRef.Get( m_dotsContainer ), 'settingsDot' );
			dot.SetSize( dotWidth, 4.0 );
		}
	}

	protected function SelectDot( index : Int32 )
	{
		var size : Int32;
		var i : Int32;
		var dot : weak< inkWidget >;
		size = inkHorizontalPanelRef.GetNumChildren( m_dotsContainer );
		for( i = 0; i < size; i += 1 )
		{
			dot = inkHorizontalPanelRef.GetWidgetByIndex( m_dotsContainer, i );
			if( i == index )
			{
				dot.SetState( 'Toggled' );
			}
			else
			{
				dot.SetState( 'Default' );
			}
		}
	}

}

class SettingsSelectorControllerListInt extends SettingsSelectorControllerList
{

	public override function Setup( entry : ConfigVar, isPreGame : Bool )
	{
		var value : ConfigVarListInt;
		var data : array< Int32 >;
		super.Setup( entry, isPreGame );
		value = ( ( ConfigVarListInt )( m_SettingsEntry ) );
		data = value.GetValues();
		PopulateDots( data.Size() );
		SelectDot( value.GetIndex() );
	}

	private override function ChangeValue( forward : Bool )
	{
		var value : ConfigVarListInt;
		var listElements : array< Int32 >;
		var index : Int32;
		var newIndex : Int32;
		value = ( ( ConfigVarListInt )( m_SettingsEntry ) );
		listElements = value.GetValues();
		index = value.GetIndex();
		newIndex = index + ( ( forward ) ? ( 1 ) : ( -1 ) );
		if( newIndex < 0 )
		{
			newIndex = listElements.Size() - 1;
		}
		else if( newIndex >= listElements.Size() )
		{
			newIndex = 0;
		}
		if( index != newIndex )
		{
			value.SetIndex( newIndex );
		}
	}

	public override function Refresh()
	{
		var value : ConfigVarListInt;
		var index : Int32;
		super.Refresh();
		value = ( ( ConfigVarListInt )( m_SettingsEntry ) );
		index = value.GetIndex();
		UpdateValueTextLanguageResources();
		if( !( value.ListHasDisplayValues() ) )
		{
			inkTextRef.SetText( m_ValueText, IntToString( value.GetValue() ) );
		}
		else
		{
			inkTextRef.SetText( m_ValueText, GetLocalizedTextByKey( value.GetDisplayValue( index ) ) );
		}
		SelectDot( index );
	}

}

class SettingsSelectorControllerListFloat extends SettingsSelectorControllerList
{

	public override function Setup( entry : ConfigVar, isPreGame : Bool )
	{
		var value : ConfigVarListFloat;
		var data : array< Float >;
		super.Setup( entry, isPreGame );
		value = ( ( ConfigVarListFloat )( m_SettingsEntry ) );
		data = value.GetValues();
		PopulateDots( data.Size() );
		SelectDot( value.GetIndex() );
	}

	private override function ChangeValue( forward : Bool )
	{
		var value : ConfigVarListFloat;
		var listElements : array< Float >;
		var index : Int32;
		var newIndex : Int32;
		value = ( ( ConfigVarListFloat )( m_SettingsEntry ) );
		listElements = value.GetValues();
		index = value.GetIndex();
		newIndex = index + ( ( forward ) ? ( 1 ) : ( -1 ) );
		if( newIndex < 0 )
		{
			newIndex = listElements.Size() - 1;
		}
		else if( newIndex >= listElements.Size() )
		{
			newIndex = 0;
		}
		if( index != newIndex )
		{
			value.SetIndex( newIndex );
		}
	}

	public override function Refresh()
	{
		var value : ConfigVarListFloat;
		var index : Int32;
		super.Refresh();
		value = ( ( ConfigVarListFloat )( m_SettingsEntry ) );
		index = value.GetIndex();
		UpdateValueTextLanguageResources();
		if( !( value.ListHasDisplayValues() ) )
		{
			inkTextRef.SetText( m_ValueText, FloatToStringPrec( value.GetValue(), 2 ) );
		}
		else
		{
			inkTextRef.SetText( m_ValueText, GetLocalizedTextByKey( value.GetDisplayValue( index ) ) );
		}
		SelectDot( index );
	}

}

class SettingsSelectorControllerListString extends SettingsSelectorControllerList
{

	public override function Setup( entry : ConfigVar, isPreGame : Bool )
	{
		var value : ConfigVarListString;
		var data : array< String >;
		super.Setup( entry, isPreGame );
		value = ( ( ConfigVarListString )( m_SettingsEntry ) );
		data = value.GetValues();
		PopulateDots( data.Size() );
		SelectDot( value.GetIndex() );
	}

	private override function ChangeValue( forward : Bool )
	{
		var value : ConfigVarListString;
		var listElements : array< String >;
		var index : Int32;
		var newIndex : Int32;
		value = ( ( ConfigVarListString )( m_SettingsEntry ) );
		listElements = value.GetValues();
		index = value.GetIndex();
		newIndex = index + ( ( forward ) ? ( 1 ) : ( -1 ) );
		if( newIndex < 0 )
		{
			newIndex = listElements.Size() - 1;
		}
		else if( newIndex >= listElements.Size() )
		{
			newIndex = 0;
		}
		if( index != newIndex )
		{
			value.SetIndex( newIndex );
		}
	}

	public override function Refresh()
	{
		var value : ConfigVarListString;
		var index : Int32;
		super.Refresh();
		value = ( ( ConfigVarListString )( m_SettingsEntry ) );
		index = value.GetIndex();
		UpdateValueTextLanguageResources();
		if( !( value.ListHasDisplayValues() ) )
		{
			inkTextRef.SetText( m_ValueText, GetLocalizedText( value.GetValue() ) );
		}
		else
		{
			inkTextRef.SetText( m_ValueText, GetLocalizedTextByKey( value.GetDisplayValue( index ) ) );
		}
		SelectDot( index );
	}

}

class SettingsSelectorControllerListName extends SettingsSelectorControllerList
{
	protected var m_realValue : weak< ConfigVarListName >;
	protected var m_currentIndex : Int32;

	public override function Setup( entry : ConfigVar, isPreGame : Bool )
	{
		var data : array< CName >;
		super.Setup( entry, isPreGame );
		m_realValue = ( ( ConfigVarListName )( m_SettingsEntry ) );
		data = m_realValue.GetValues();
		m_currentIndex = m_realValue.GetIndex();
		PopulateDots( data.Size() );
		SelectDot( m_currentIndex );
		Refresh();
	}

	private override function ChangeValue( forward : Bool )
	{
		var listElements : array< CName >;
		var index : Int32;
		var newIndex : Int32;
		listElements = m_realValue.GetValues();
		index = m_currentIndex;
		newIndex = index + ( ( forward ) ? ( 1 ) : ( -1 ) );
		if( newIndex < 0 )
		{
			newIndex = listElements.Size() - 1;
		}
		else if( newIndex >= listElements.Size() )
		{
			newIndex = 0;
		}
		if( index != newIndex )
		{
			m_currentIndex = newIndex;
			m_realValue.SetIndex( newIndex );
		}
	}

	public override function Refresh()
	{
		var params : inkTextParams;
		var varValue : CName;
		super.Refresh();
		UpdateValueTextLanguageResources();
		if( !( m_realValue.ListHasDisplayValues() ) )
		{
			inkTextRef.SetText( m_ValueText, GetLocalizedTextByKey( m_realValue.GetValueFor( m_currentIndex ) ) );
		}
		else
		{
			varValue = m_realValue.GetDisplayValue( m_currentIndex );
			if( varValue == 'UI-Settings-Language-Russian' && m_realValue.GetName() == 'VoiceOver' )
			{
				varValue = 'UI-Settings-Language-Russian2';
			}
			if( m_additionalText == '' )
			{
				inkTextRef.SetText( m_ValueText, GetLocalizedTextByKey( varValue ) );
			}
			else
			{
				params = new inkTextParams;
				params.AddLocalizedString( "description", GetLocalizedTextByKey( varValue ) );
				params.AddLocalizedString( "additional_text", ( ( String )( m_additionalText ) ) );
				inkTextRef.SetLocalizedTextScript( m_ValueText, "LocKey#76949", params );
			}
		}
		SelectDot( m_currentIndex );
	}

}

class SettingsSelectorControllerLanguagesList extends SettingsSelectorControllerListName
{
	protected editable var m_downloadButton : inkWidgetRef;
	private var m_descriptionText : inkTextRef;
	private var m_isVoiceOverInstalled : Bool;
	private var m_currentSetIndex : Int32;

	public function SetDownloadButtonVisible( visible : Bool )
	{
		inkWidgetRef.SetVisible( m_downloadButton, visible );
	}

	public function SetDownloadButtonEnabled( enabled : Bool )
	{
		inkWidgetRef.SetOpacity( m_downloadButton, ( ( enabled ) ? ( 1.0 ) : ( 0.30000001 ) ) );
	}

	public override function Setup( entry : ConfigVar, isPreGame : Bool )
	{
		super.Setup( entry, isPreGame );
		m_isVoiceOverInstalled = IsLanguageVoicePackInstalled( m_realValue.GetValueFor( m_currentIndex ) );
		m_currentSetIndex = m_currentIndex;
		SetDownloadButtonVisible( !( m_isVoiceOverInstalled ) );
		Refresh();
	}

	protected event OnInitialize()
	{
		super.OnInitialize();
		m_isVoiceOverInstalled = false;
		if( inkWidgetRef.IsValid( m_downloadButton ) )
		{
			inkWidgetRef.RegisterToCallback( m_downloadButton, 'OnRelease', this, 'OnDownload' );
		}
	}

	private override function ChangeValue( forward : Bool )
	{
		var listElements : array< CName >;
		var index : Int32;
		var newIndex : Int32;
		listElements = m_realValue.GetValues();
		index = m_currentIndex;
		newIndex = index + ( ( forward ) ? ( 1 ) : ( -1 ) );
		if( newIndex < 0 )
		{
			newIndex = listElements.Size() - 1;
		}
		else if( newIndex >= listElements.Size() )
		{
			newIndex = 0;
		}
		if( index != newIndex )
		{
			m_currentIndex = newIndex;
			m_isVoiceOverInstalled = IsLanguageVoicePackInstalled( m_realValue.GetValueFor( m_currentIndex ) );
			SetDownloadButtonVisible( !( m_isVoiceOverInstalled ) );
			ResetAdditionalText();
			if( m_isVoiceOverInstalled )
			{
				if( m_currentIndex != m_currentSetIndex )
				{
					m_currentSetIndex = m_currentIndex;
					m_realValue.SetIndex( m_currentIndex );
				}
			}
			else
			{
				SetAdditionalText( 'LocKey#76946' );
			}
			Refresh();
		}
	}

	public function RegisterDownloadButtonHovers( descriptionText : inkTextRef )
	{
		m_descriptionText = descriptionText;
		inkWidgetRef.RegisterToCallback( m_downloadButton, 'OnHoverOver', this, 'OnSettingHoverOver' );
		inkWidgetRef.RegisterToCallback( m_downloadButton, 'OnHoverOut', this, 'OnSettingHoverOut' );
	}

	protected event OnDownload( e : inkPointerEvent )
	{
		if( e.IsAction( 'click' ) )
		{
			RequestInstallLanguagePackDialog( m_realValue.GetValueFor( m_currentIndex ) );
		}
	}

	public override function Refresh()
	{
		if( m_isVoiceOverInstalled )
		{
			ResetAdditionalText();
		}
		else
		{
			SetAdditionalText( 'LocKey#76946' );
		}
		super.Refresh();
	}

	protected event OnSettingHoverOver( e : inkPointerEvent )
	{
		inkTextRef.SetLocalizedText( m_descriptionText, 'Will install this language pack' );
		inkTextRef.SetVisible( m_descriptionText, true );
	}

	protected event OnSettingHoverOut( e : inkPointerEvent )
	{
		inkTextRef.SetVisible( m_descriptionText, false );
	}

}

