class CyberwareInventoryMiniGrid extends inkLogicController
{
	private editable var m_isLeftAligned : Bool;
	private editable var m_gridContainer : inkUniformGridRef;
	private editable var m_label : inkTextRef;
	private editable var m_isNew : inkWidgetRef;
	private var m_selectedSlotIndex : Int32;
	var m_equipArea : gamedataEquipmentArea;
	private var m_parentObject : IScriptable;
	private var m_onRealeaseCallbackName : CName;
	private var m_opacityAnimation : inkAnimProxy;
	private var m_marginAnimation : inkAnimProxy;
	private var m_labelAnimation : inkAnimProxy;
	private var m_labelPulse : PulseAnimation;
	private var m_margin : inkMargin;
	private var m_targetMargin : inkMargin;
	private var m_parent : inkCompoundRef;
	private var m_player : weak< PlayerPuppet >;
	private var minigridAnimation : inkAnimProxy;
	private var m_screen : CyberwareScreenType;
	private var m_displayContext : ItemDisplayContextData;
	private var m_gridData : array< weak< InventoryItemDisplayController > >;
	private var m_root : weak< inkWidget >;

	protected event OnInitialize()
	{
		m_root = GetRootWidget();
		RegisterToCallback( 'OnStateChanged', this, 'OnStateChanged' );
		inkTextRef.SetVisible( m_label, true );
		m_root.RegisterToCallback( 'OnEnter', this, 'OnHoverOverCategory' );
		m_root.RegisterToCallback( 'OnLeave', this, 'OnHoverOutCategory' );
		inkTextRef.RegisterToCallback( m_label, 'OnHoverOver', this, 'OnHoverOverCategoryLabel' );
		inkTextRef.RegisterToCallback( m_label, 'OnHoverOut', this, 'OnHoverOutCategoryLabel' );
	}

	protected event OnUninitialize()
	{
		RemoveElements( 0 );
		m_root.UnregisterFromCallback( 'OnEnter', this, 'OnHoverOverCategory' );
		m_root.UnregisterFromCallback( 'OnLeave', this, 'OnHoverOutCategory' );
		inkTextRef.UnregisterFromCallback( m_label, 'OnHoverOver', this, 'OnHoverOverCategoryLabel' );
		inkTextRef.UnregisterFromCallback( m_label, 'OnHoverOut', this, 'OnHoverOutCategoryLabel' );
	}

	protected event OnHoverOverCategory( e : inkPointerEvent )
	{
		if( inkTextRef.GetState( m_label ) == 'New' )
		{
			return false;
		}
		inkTextRef.SetState( m_label, 'Hover' );
	}

	protected event OnHoverOutCategory( e : inkPointerEvent )
	{
		if( inkTextRef.GetState( m_label ) == 'New' )
		{
			return false;
		}
		inkTextRef.SetState( m_label, 'Default' );
	}

	protected event OnHoverOverCategoryLabel( e : inkPointerEvent )
	{
		var hoverOverEvent : CategoryHoverOverEvent;
		hoverOverEvent = new CategoryHoverOverEvent;
		hoverOverEvent.equipArea = m_equipArea;
		QueueEvent( hoverOverEvent );
	}

	protected event OnHoverOutCategoryLabel( e : inkPointerEvent )
	{
		var hoverOutEvent : CategoryHoverOutEvent;
		hoverOutEvent = new CategoryHoverOutEvent;
		QueueEvent( hoverOutEvent );
	}

	public function HoveredAttribute( player : PlayerPuppet, attribute : gamedataStatType )
	{
		var i, j : Int32;
		var item : weak< InventoryItemDisplayController >;
		var stats : array< SItemStackRequirementData >;
		var stat : SItemStackRequirementData;
		var armorStats : array< StatViewData >;
		var armorStat : StatViewData;
		var hasItem : Bool;
		m_player = player;
		for( i = m_gridData.Size() - 1; i >= 0; i -= 1 )
		{
			item = m_gridData[ i ];
			if( attribute == gamedataStatType.Armor )
			{
				armorStats = InventoryItemData.GetPrimaryStats( item.GetItemData() );
				for( j = 0; j < armorStats.Size(); j += 1 )
				{
					armorStat = armorStats[ j ];
					if( armorStat.type == gamedataStatType.Armor && ( armorStat.valueF > 0.0 ) )
					{
						HighlightSlot( i );
						hasItem = true;
						break;
					}
				}
			}
			else
			{
				stats = RPGManager.GetEquipRequirements( player, InventoryItemData.GetGameItemData( item.GetItemData() ) );
				for( j = 0; j < stats.Size(); j += 1 )
				{
					stat = stats[ j ];
					if( stat.statType == attribute && ( stat.requiredValue > 0.0 ) )
					{
						HighlightSlot( i );
						hasItem = true;
						break;
					}
				}
			}
		}
		if( hasItem )
		{
			OpacityShow();
		}
		else
		{
			OpacityHide( true );
		}
	}

	private function SetOpacityDumb( hide, shouldDim : Bool, duration, delay : Float )
	{
		var opacityInterpolator : inkAnimTransparency;
		var animation : inkAnimDef;
		var options : inkAnimOptions;
		var time, endOpacity : Float;
		if( m_opacityAnimation != NULL )
		{
			m_opacityAnimation.Stop();
		}
		if( shouldDim )
		{
			time = ( m_root.GetOpacity() - 0.1 ) / 0.89999998;
			time = ( ( hide ) ? ( time ) : ( ( 1.0 - time ) ) ) * 0.5;
			endOpacity = ( ( hide ) ? ( 0.1 ) : ( 1.0 ) );
		}
		else
		{
			time = m_root.GetOpacity();
			time = ( ( hide ) ? ( time ) : ( ( 1.0 - time ) ) ) * duration;
			endOpacity = ( ( hide ) ? ( 0.0 ) : ( 1.0 ) );
		}
		opacityInterpolator = new inkAnimTransparency;
		opacityInterpolator.SetDuration( time );
		opacityInterpolator.SetStartTransparency( m_root.GetOpacity() );
		opacityInterpolator.SetEndTransparency( endOpacity );
		opacityInterpolator.SetType( inkanimInterpolationType.Quintic );
		opacityInterpolator.SetMode( ( ( hide ) ? ( inkanimInterpolationMode.EasyOut ) : ( inkanimInterpolationMode.EasyInOut ) ) );
		animation = new inkAnimDef;
		animation.AddInterpolator( opacityInterpolator );
		options.executionDelay = delay;
		m_opacityAnimation = m_root.PlayAnimationWithOptions( animation, options );
	}

	public function OpacityHide( optional shouldDim : Bool )
	{
		SetOpacityDumb( true, shouldDim, 0.5, 0.0 );
	}

	public function OpacityFullHide()
	{
		m_root.SetVisible( false );
	}

	public function OpacityFullShow()
	{
		m_root.SetVisible( true );
	}

	public function OpacityShow( optional delay : Float )
	{
		SetOpacityDumb( false, false, 0.5, delay );
	}

	public function SetOrientation( orientation : inkEOrientation )
	{
		inkUniformGridRef.SetOrientation( m_gridContainer, orientation );
	}

	public function SetTargetMargin( margin : inkMargin, parent : inkCompoundRef )
	{
		m_margin = inkCompoundRef.GetMargin( parent );
		m_targetMargin = margin;
		m_parent = parent;
		m_root.SetOpacity( 0.0 );
	}

	public function SetupData( equipArea : gamedataEquipmentArea, const playerEquipAreaInventory : ref< array< weak< UIInventoryItem > > >, parent : IScriptable, onRealeaseCallbackName : CName, screen : CyberwareScreenType, hasMods : Bool, displayContext : ItemDisplayContextData, optional inventoryManager : InventoryDataManagerV2, optional player : PlayerPuppet )
	{
		var i, limit : Int32;
		var gridListItem : weak< InventoryItemDisplayController >;
		var slotUserData : SlotUserData;
		var visibleWhenLocked : Bool;
		var itemUpgrade : Item_Record;
		var itemUpgradeQuality : gamedataQuality;
		var costData : CyberwareUpgradeCostData;
		m_player = player;
		m_parentObject = parent;
		m_equipArea = equipArea;
		m_onRealeaseCallbackName = onRealeaseCallbackName;
		m_displayContext = displayContext;
		limit = playerEquipAreaInventory.Size();
		inkUniformGridRef.SetWrappingWidgetCount( m_gridContainer, ( ( Uint32 )( limit ) ) );
		while( m_gridData.Size() > 0 )
		{
			gridListItem = m_gridData.PopBack();
			inkUniformGridRef.RemoveChild( m_gridContainer, gridListItem.GetRootWidget() );
		}
		for( i = 0; i < limit; i += 1 )
		{
			slotUserData = new SlotUserData;
			slotUserData.item = playerEquipAreaInventory[ i ];
			slotUserData.index = i;
			slotUserData.area = equipArea;
			slotUserData.isLocked = inventoryManager.IsSlotLocked( equipArea, i, visibleWhenLocked );
			slotUserData.visibleWhenLocked = visibleWhenLocked;
			slotUserData.screen = screen;
			slotUserData.isPerkRequired = IsEquipmentAreaRequiringPerk( equipArea ) && ( i == ( limit - 1 ) );
			slotUserData.canUpgrade = RPGManager.CanUpgradeCyberware( player, slotUserData.item.GetID(), slotUserData.item.IsEquipped(), gamedataQuality.Invalid, itemUpgradeQuality, itemUpgrade, costData );
			slotUserData.upgradeItem = itemUpgrade;
			slotUserData.upgradeItemQuality = itemUpgradeQuality;
			ItemDisplayUtils.SpawnCommonSlotAsync( this, m_gridContainer, 'itemDisplay', 'OnSlotSpawned', slotUserData );
		}
		UnselectSlot();
		UpdateTitle( GetAreaHeader( equipArea ) );
	}

	public function RefreshisNewPreview( hasNew : Bool )
	{
		inkWidgetRef.SetVisible( m_isNew, hasNew );
	}

	protected event OnStateChanged( widget : weak< inkWidget >, oldState : CName, newState : CName )
	{
		var i : Int32;
		for( i = 0; i < m_gridData.Size(); i += 1 )
		{
			m_gridData[ i ].GetRootWidget().SetState( newState );
		}
	}

	public function HighlightSlot( index : Int32, optional animatedHighlight : Bool )
	{
		m_gridData[ index ].SetHighlighted( true );
		if( m_screen == CyberwareScreenType.Ripperdoc && animatedHighlight )
		{
			m_gridData[ index ].SetHighlightedCyberwareSlot( true );
		}
	}

	public function UnhighlightSlot( index : Int32 )
	{
		m_gridData[ index ].SetHighlighted( false );
		if( m_screen == CyberwareScreenType.Ripperdoc )
		{
			m_gridData[ index ].SetHighlightedCyberwareSlot( false );
		}
	}

	public function HighlightSelectedSlot()
	{
		if( ( m_selectedSlotIndex >= 0 ) && ( m_selectedSlotIndex < m_gridData.Size() ) )
		{
			m_gridData[ m_selectedSlotIndex ].SetHighlighted( true );
			if( m_screen == CyberwareScreenType.Ripperdoc )
			{
				m_gridData[ m_selectedSlotIndex ].SetHighlightedCyberwareSlot( true );
			}
		}
	}

	public function UnhighlightSelectedSlot()
	{
		if( ( m_selectedSlotIndex >= 0 ) && ( m_selectedSlotIndex < m_gridData.Size() ) )
		{
			m_gridData[ m_selectedSlotIndex ].SetHighlighted( false );
			if( m_screen == CyberwareScreenType.Ripperdoc )
			{
				m_gridData[ m_selectedSlotIndex ].SetHighlightedCyberwareSlot( false );
			}
		}
	}

	public function UnhighlightAllSlots()
	{
		var i : Int32;
		for( i = 0; i < m_gridData.Size(); i += 1 )
		{
			if( i != m_selectedSlotIndex )
			{
				m_gridData[ i ].SetHighlighted( false );
				if( m_screen == CyberwareScreenType.Ripperdoc )
				{
					m_gridData[ i ].SetHighlightedCyberwareSlot( false );
				}
			}
		}
	}

	public function GetSlotIndex( slot : weak< InventoryItemDisplayController > ) : Int32
	{
		var i : Int32;
		for( i = 0; i < m_gridData.Size(); i += 1 )
		{
			if( m_gridData[ i ] == slot )
			{
				return i;
			}
		}
		return -1;
	}

	public function PlayEquipAnimation( index : Int32 )
	{
		if( ( index >= 0 ) && ( index < m_gridData.Size() ) )
		{
			m_gridData[ index ].PlayEquipFeedback();
		}
	}

	public function SelectSlot( index : Int32 )
	{
		UnselectSlot();
		if( ( index >= 0 ) && ( index < m_gridData.Size() ) )
		{
			m_selectedSlotIndex = index;
			m_gridData[ m_selectedSlotIndex ].SetHighlighted( true );
			if( m_screen == CyberwareScreenType.Ripperdoc )
			{
				m_gridData[ m_selectedSlotIndex ].SetHighlightedCyberwareSlot( true );
			}
		}
	}

	public function UnselectSlot()
	{
		if( ( m_selectedSlotIndex >= 0 ) && ( m_selectedSlotIndex < m_gridData.Size() ) )
		{
			m_gridData[ m_selectedSlotIndex ].SetHighlighted( false );
			if( m_screen == CyberwareScreenType.Ripperdoc )
			{
				m_gridData[ m_selectedSlotIndex ].SetHighlightedCyberwareSlot( false );
			}
		}
		m_selectedSlotIndex = -1;
	}

	public function GetSelectedSlotIndex() : Int32
	{
		return m_selectedSlotIndex;
	}

	public function GetSelectedSlotData() : weak< UIInventoryItem >
	{
		return GetSlotData( m_selectedSlotIndex );
	}

	public function GetEquippedData( itemID : ItemID ) : weak< UIInventoryItem >
	{
		return GetSlotData( GetSlotToEquipe( itemID ) );
	}

	public function GetSlotData( slotIndex : Int32 ) : weak< UIInventoryItem >
	{
		var result : weak< UIInventoryItem >;
		if( ( slotIndex >= 0 ) && ( slotIndex < m_gridData.Size() ) )
		{
			result = m_gridData[ slotIndex ].GetUIInventoryItem();
		}
		return result;
	}

	public function GetSlotToEquipe( itemID : ItemID ) : Int32
	{
		var cyberwareType : CName;
		var i, emptySlot : Int32;
		emptySlot = -1;
		cyberwareType = TweakDBInterface.GetCName( ItemID.GetTDBID( itemID ) + T".cyberwareType", '' );
		for( i = m_gridData.Size() - 1; i >= 0; i -= 1 )
		{
			if( ( m_gridData[ i ].GetUIInventoryItem() == NULL ) && !( m_gridData[ i ].IsPerkRequiredCyberware() ) )
			{
				emptySlot = m_gridData[ i ].GetSlotIndex();
				continue;
			}
			if( cyberwareType == TweakDBInterface.GetCName( m_gridData[ i ].GetUIInventoryItem().GetTweakDBID() + T".cyberwareType", '' ) && !( m_gridData[ i ].IsPerkRequiredCyberware() ) )
			{
				return m_gridData[ i ].GetSlotIndex();
			}
		}
		return ( ( emptySlot != -1 ) ? ( emptySlot ) : ( ( ( m_selectedSlotIndex != -1 ) ? ( m_selectedSlotIndex ) : ( 0 ) ) ) );
	}

	public function GetEquipmentArea() : gamedataEquipmentArea
	{
		return m_equipArea;
	}

	public function IsLeftSide() : Bool
	{
		return m_isLeftAligned;
	}

	public function GetLastSlot() : weak< inkWidget >
	{
		return m_gridData.Last().GetRootWidget();
	}

	public function GetFirstSlot() : weak< inkWidget >
	{
		return m_gridData[ 0 ].GetRootWidget();
	}

	public function UpdateData( equipArea : gamedataEquipmentArea, playerEquipAreaInventory : ref< array< weak< UIInventoryItem > > >, optional screen : CyberwareScreenType )
	{
		var i, limit : Int32;
		var gridListItem : InventoryItemDisplayController;
		var itemUpgrade : Item_Record;
		var itemUpgradeQuality : gamedataQuality;
		var costData : CyberwareUpgradeCostData;
		limit = playerEquipAreaInventory.Size();
		m_equipArea = equipArea;
		inkUniformGridRef.SetWrappingWidgetCount( m_gridContainer, ( ( Uint32 )( limit ) ) );
		RemoveElements( limit );
		while( m_gridData.Size() < limit )
		{
			gridListItem = ( ( InventoryItemDisplayController )( ItemDisplayUtils.SpawnCommonSlotController( this, inkUniformGridRef.Get( m_gridContainer ), 'itemDisplay' ) ) );
			gridListItem.RegisterToCallback( 'OnRelease', m_parentObject, m_onRealeaseCallbackName );
			m_gridData.PushBack( gridListItem );
		}
		for( i = 0; i < limit; i += 1 )
		{
			gridListItem = m_gridData[ i ];
			gridListItem.Setup( playerEquipAreaInventory[ i ], m_equipArea, "", i, m_displayContext );
			gridListItem.SetUpgradableCyberware( RPGManager.CanUpgradeCyberware( m_player, playerEquipAreaInventory[ i ].GetID(), playerEquipAreaInventory[ i ].IsEquipped(), gamedataQuality.Invalid, itemUpgradeQuality, itemUpgrade, costData ) );
		}
		UnselectSlot();
	}

	protected event OnSlotSpawned( widget : inkWidget, userData : IScriptable )
	{
		var gridListItem : InventoryItemDisplayController;
		var slotUserData : SlotUserData;
		slotUserData = ( ( SlotUserData )( userData ) );
		gridListItem = ( ( InventoryItemDisplayController )( widget.GetController() ) );
		gridListItem.SetUpgradableCyberware( slotUserData.canUpgrade );
		gridListItem.Setup( slotUserData.item, slotUserData.area, "", slotUserData.index, m_displayContext );
		gridListItem.RegisterToCallback( 'OnRelease', m_parentObject, m_onRealeaseCallbackName );
		if( ( slotUserData.isPerkRequired && slotUserData.isLocked ) && ( slotUserData.item == NULL ) )
		{
			gridListItem.SetPerkRequiredCyberware( slotUserData.area );
		}
		else
		{
			gridListItem.SetLocked( slotUserData.isLocked, slotUserData.visibleWhenLocked );
		}
		m_screen = slotUserData.screen;
		if( m_screen == CyberwareScreenType.Inventory )
		{
			if( slotUserData.item == NULL )
			{
				gridListItem.SetCyberwareEmptyInInventroy();
				widget.SetState( 'ReadOnly' );
			}
			else
			{
				gridListItem.SetCyberwarePrieviewInInventroy();
			}
		}
		m_gridData.PushBack( gridListItem );
	}

	private function UpdateTitle( const label : ref< String > )
	{
		inkTextRef.SetText( m_label, label );
	}

	public function GetInventoryItemDisplays() : array< weak< InventoryItemDisplayController > >
	{
		return m_gridData;
	}

	private function RemoveElements( limit : Int32 )
	{
		var gridListItem : weak< InventoryItemDisplayController >;
		while( m_gridData.Size() > limit )
		{
			gridListItem = m_gridData.PopBack();
			gridListItem.UnregisterFromCallback( 'OnRelease', m_parentObject, m_onRealeaseCallbackName );
			inkUniformGridRef.RemoveChild( m_gridContainer, gridListItem.GetRootWidget() );
		}
	}

	private function GetAreaHeader( area : gamedataEquipmentArea ) : String
	{
		var record : EquipmentArea_Record;
		var label : String;
		record = TweakDBInterface.GetEquipmentAreaRecord( TDBID.Create( "EquipmentArea." + EnumValueToString( "gamedataEquipmentArea", ( ( Int32 )( area ) ) ) ) );
		label = record.LocalizedName();
		if( label == "" )
		{
			label = EnumValueToString( "gamedataEquipmentArea", ( ( Int32 )( area ) ) );
		}
		return label;
	}

	public function ResetPosition( optional immediate : Bool, optional duration : Float )
	{
		if( m_marginAnimation != NULL )
		{
			m_marginAnimation.Stop();
		}
		if( inkCompoundRef.GetMargin( m_parent ) != m_margin )
		{
			if( immediate )
			{
				SetPositionImmediate( m_margin );
			}
			else
			{
				if( duration != 0.0 )
				{
					SetPosition_Animation( m_margin, duration, true );
				}
				else
				{
					SetPosition_Animation( m_margin, 0.30000001, true );
				}
			}
			AnimateLabel( false );
		}
	}

	public function SetPosition( margin : inkMargin, duration : Float )
	{
		var animation : inkAnimDef;
		var marginInterpolator : inkAnimMargin;
		if( m_marginAnimation != NULL )
		{
			m_marginAnimation.Stop();
		}
		if( m_isLeftAligned )
		{
			margin.left = ( margin.left - 290.0 ) + ( ( Float )( ( ( m_gridData.Size() - 1 ) * 225 ) ) );
		}
		marginInterpolator = new inkAnimMargin;
		marginInterpolator.SetDuration( duration );
		marginInterpolator.SetStartMargin( inkCompoundRef.GetMargin( m_parent ) );
		marginInterpolator.SetEndMargin( margin );
		marginInterpolator.SetType( inkanimInterpolationType.Quintic );
		marginInterpolator.SetMode( inkanimInterpolationMode.EasyInOut );
		animation = new inkAnimDef;
		animation.AddInterpolator( marginInterpolator );
		m_marginAnimation = inkCompoundRef.PlayAnimation( m_parent, animation );
		AnimateLabel( true );
	}

	public function SetPosition_Animation( margin : inkMargin, duration : Float, optional isReversed : Bool, optional customOffset : Float, optional interpolationMode : inkanimInterpolationMode, optional interpolationType : inkanimInterpolationType )
	{
		var offset : Float;
		var animation : inkAnimDef;
		var targetMargin : inkMargin;
		var marginInterpolator : inkAnimMargin;
		var transparencyInterpolator : inkAnimTransparency;
		var translationInterpolator : inkAnimTranslation;
		offset = ( ( customOffset != 0.0 ) ? ( customOffset ) : ( 200.0 ) );
		offset *= ( ( isReversed ) ? ( -1.0 ) : ( 1.0 ) );
		if( m_marginAnimation != NULL )
		{
			( ( m_marginAnimation.IsPlaying() ) ? ( m_marginAnimation.GotoEndAndStop() ) : ( m_marginAnimation.Stop() ) );
		}
		if( m_isLeftAligned && !( isReversed ) )
		{
			margin.left = ( margin.left - 290.0 ) + ( ( Float )( ( ( m_gridData.Size() - 1 ) * 225 ) ) );
		}
		if( isReversed )
		{
			targetMargin = m_margin;
		}
		else
		{
			targetMargin = margin;
		}
		if( targetMargin == inkCompoundRef.GetMargin( m_parent ) )
		{
			return;
		}
		animation = new inkAnimDef;
		transparencyInterpolator = new inkAnimTransparency;
		transparencyInterpolator.SetDuration( duration / 2.0 );
		transparencyInterpolator.SetStartTransparency( 1.0 );
		transparencyInterpolator.SetEndTransparency( 0.0 );
		transparencyInterpolator.SetMode( interpolationMode );
		transparencyInterpolator.SetType( interpolationType );
		animation.AddInterpolator( transparencyInterpolator );
		translationInterpolator = new inkAnimTranslation;
		translationInterpolator.SetDuration( duration / 2.0 );
		translationInterpolator.SetStartTranslation( Vector2( 0.0, 0.0 ) );
		translationInterpolator.SetEndTranslation( Vector2( offset, 0.0 ) );
		translationInterpolator.SetMode( interpolationMode );
		translationInterpolator.SetType( interpolationType );
		animation.AddInterpolator( translationInterpolator );
		marginInterpolator = new inkAnimMargin;
		marginInterpolator.SetDuration( 0.0 );
		marginInterpolator.SetStartDelay( duration / 2.0 );
		marginInterpolator.SetStartMargin( inkCompoundRef.GetMargin( m_parent ) );
		marginInterpolator.SetEndMargin( targetMargin );
		animation.AddInterpolator( marginInterpolator );
		transparencyInterpolator = new inkAnimTransparency;
		transparencyInterpolator.SetDuration( duration / 2.0 );
		transparencyInterpolator.SetStartDelay( duration / 2.0 );
		transparencyInterpolator.SetStartTransparency( 0.0 );
		transparencyInterpolator.SetEndTransparency( 1.0 );
		transparencyInterpolator.SetMode( interpolationMode );
		transparencyInterpolator.SetType( interpolationType );
		animation.AddInterpolator( transparencyInterpolator );
		translationInterpolator = new inkAnimTranslation;
		translationInterpolator.SetDuration( duration / 2.0 );
		translationInterpolator.SetStartDelay( duration / 2.0 );
		translationInterpolator.SetStartTranslation( Vector2( offset, 0.0 ) );
		translationInterpolator.SetEndTranslation( Vector2( 0.0, 0.0 ) );
		translationInterpolator.SetMode( interpolationMode );
		translationInterpolator.SetType( interpolationType );
		animation.AddInterpolator( translationInterpolator );
		m_marginAnimation = inkCompoundRef.PlayAnimation( m_parent, animation );
		AnimateLabel( true );
	}

	public function PlayIntroAnimation( duration : Float, interpolationMode : inkanimInterpolationMode, interpolationType : inkanimInterpolationType )
	{
		var offset : Float;
		var animation : inkAnimDef;
		var transparencyInterpolator : inkAnimTransparency;
		var translationInterpolator : inkAnimTranslation;
		if( m_marginAnimation != NULL )
		{
			m_marginAnimation.Stop();
		}
		offset = ( ( m_isLeftAligned ) ? ( -200.0 ) : ( 200.0 ) );
		animation = new inkAnimDef;
		transparencyInterpolator = new inkAnimTransparency;
		transparencyInterpolator.SetDuration( duration );
		transparencyInterpolator.SetStartTransparency( 0.0 );
		transparencyInterpolator.SetEndTransparency( 1.0 );
		transparencyInterpolator.SetMode( interpolationMode );
		transparencyInterpolator.SetType( interpolationType );
		animation.AddInterpolator( transparencyInterpolator );
		translationInterpolator = new inkAnimTranslation;
		translationInterpolator.SetDuration( duration );
		translationInterpolator.SetStartTranslation( Vector2( offset, 0.0 ) );
		translationInterpolator.SetEndTranslation( Vector2( 0.0, 0.0 ) );
		translationInterpolator.SetMode( interpolationMode );
		translationInterpolator.SetType( interpolationType );
		animation.AddInterpolator( translationInterpolator );
		m_marginAnimation = m_root.PlayAnimation( animation );
	}

	public function PlayMinigridAnim( playReverse : Bool )
	{
		var options : inkAnimOptions;
		if( minigridAnimation != NULL )
		{
			minigridAnimation.Stop();
		}
		options.executionDelay = 0.40000001;
		options.playReversed = playReverse;
		minigridAnimation = PlayLibraryAnimation( 'test', options );
	}

	public function SetPositionImmediate( margin : inkMargin )
	{
		if( m_marginAnimation != NULL )
		{
			m_marginAnimation.Stop();
			m_marginAnimation = NULL;
		}
		inkCompoundRef.SetMargin( m_parent, margin );
	}

	public function SetLabelImmediate( show : Bool )
	{
		if( m_labelAnimation != NULL )
		{
			m_labelAnimation.Stop();
			m_labelAnimation = NULL;
		}
		inkTextRef.SetOpacity( m_label, ( ( show ) ? ( 1.0 ) : ( 0.0 ) ) );
	}

	private function AnimateLabel( hide : Bool )
	{
		var opacityInterpolator : inkAnimTransparency;
		var animation : inkAnimDef;
		var time : Float;
		if( m_labelAnimation != NULL )
		{
			m_labelAnimation.Stop();
		}
		time = inkTextRef.GetOpacity( m_label );
		time = ( ( hide ) ? ( time ) : ( ( 1.0 - time ) ) ) * 0.75;
		opacityInterpolator = new inkAnimTransparency;
		opacityInterpolator.SetDuration( time );
		opacityInterpolator.SetStartTransparency( inkTextRef.GetOpacity( m_label ) );
		opacityInterpolator.SetEndTransparency( ( ( hide ) ? ( 0.0 ) : ( 1.0 ) ) );
		opacityInterpolator.SetType( inkanimInterpolationType.Quintic );
		opacityInterpolator.SetMode( inkanimInterpolationMode.EasyInOut );
		animation = new inkAnimDef;
		animation.AddInterpolator( opacityInterpolator );
		m_labelAnimation = inkTextRef.PlayAnimation( m_label, animation );
		inkWidgetRef.PlayAnimation( m_isNew, animation );
	}

	public function SetInteractive( interactive : Bool )
	{
		var i : Int32;
		for( i = 0; i < m_gridData.Size(); i += 1 )
		{
			m_gridData[ i ].SetInteractive( interactive );
		}
	}

	private function IsEquipmentAreaRequiringPerk( equipmentArea : gamedataEquipmentArea ) : Bool
	{
		return equipmentArea == gamedataEquipmentArea.HandsCW || equipmentArea == gamedataEquipmentArea.MusculoskeletalSystemCW;
	}

}

class SlotUserData extends IScriptable
{
	var item : weak< UIInventoryItem >;
	var index : Int32;
	var area : gamedataEquipmentArea;
	var isLocked : Bool;
	var visibleWhenLocked : Bool;
	var screen : CyberwareScreenType;
	var isPerkRequired : Bool;
	var canUpgrade : Bool;
	var upgradeItem : weak< Item_Record >;
	var upgradeItemQuality : gamedataQuality;
}

class GridUserData extends IScriptable
{
	var equipArea : gamedataEquipmentArea;
	var align : inkEHorizontalAlign;
	var parent : inkCompoundRef;
}

class CategoryHoverOverEvent extends Event
{
	var equipArea : gamedataEquipmentArea;
}

class CategoryHoverOutEvent extends Event
{
}

