#include "stdafx.h"

#include "IUIScene_AbstractContainerMenu.h"

#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h"
#include "..\..\..\Minecraft.World\net.minecraft.world.item.h"
#include "..\..\..\Minecraft.World\net.minecraft.world.item.crafting.h"
#include "..\..\..\Minecraft.World\net.minecraft.world.level.tile.entity.h"
#include "..\..\MultiplayerLocalPlayer.h"
#include "..\..\Minecraft.h"

#ifdef __ORBIS__
#include <pad.h>
#endif

#ifdef _WINDOWS64
#include "..\..\KeyboardMouseInput.h"
#endif

IUIScene_AbstractContainerMenu::IUIScene_AbstractContainerMenu()
{
	m_menu = NULL;
	m_autoDeleteMenu = false;
	m_lastPointerLabelSlot = NULL;

	m_pointerPos.x = 0.0f;
	m_pointerPos.y = 0.0f;

}

IUIScene_AbstractContainerMenu::~IUIScene_AbstractContainerMenu()
{
	// Delete associated menu if we were requested to on initialisation. Most menus are
	// created just before calling CXuiSceneAbstractContainer::Initialize, but the player's inventorymenu
	// is also passed directly and we don't want to go deleting that
	if( m_autoDeleteMenu ) delete m_menu;
}

void IUIScene_AbstractContainerMenu::Initialize(int iPad, AbstractContainerMenu* menu, bool autoDeleteMenu, int startIndex,ESceneSection firstSection,ESceneSection maxSection, bool bNavigateBack)
{
	assert( menu != NULL );

	m_menu = menu;
	m_autoDeleteMenu = autoDeleteMenu;

	Minecraft::GetInstance()->localplayers[iPad]->containerMenu = menu;

	// 4J WESTY - New tool tips to support pointer prototype.
	//UpdateTooltips();
	// Default tooltips.
	for ( int i = 0; i < eToolTipNumButtons; ++i )
	{
		m_aeToolTipSettings[ i ] = eToolTipNone;
	}
	// 4J-PB - don't set the eToolTipPickupPlace_OLD here - let the timer do it.
	/*SetToolTip( eToolTipButtonA, eToolTipPickupPlace_OLD );*/
	SetToolTip( eToolTipButtonB, eToolTipExit );
	SetToolTip( eToolTipButtonA, eToolTipNone );
	SetToolTip( eToolTipButtonX, eToolTipNone );
	SetToolTip( eToolTipButtonY, eToolTipNone );

	// 4J WESTY : To indicate if pointer has left menu window area.
	m_bPointerOutsideMenu = false;

	// 4J Stu - Store the enum range for the current scene
	m_eFirstSection = firstSection;
	m_eMaxSection = maxSection;

	m_iConsectiveInputTicks = 0;

	m_bNavigateBack = bNavigateBack;

	// Put the pointer over first item in use row to start with.
#ifdef TAP_DETECTION
	m_eCurrSection = firstSection;
	m_eCurrTapState = eTapStateNoInput;
	m_iCurrSlotX = 0;
	m_iCurrSlotY = 0;
#endif // TAP_DETECTION
	// 
	// 	for(int i=0;i<XUSER_MAX_COUNT;i++)
	// 	{
	// 		m_bFirstTouchStored[i]=false;
	// 	}

#ifdef __ORBIS__
	for(int i=0;i<XUSER_MAX_COUNT;i++)
	{
		m_bFirstTouchStored[i]=false;
	}
#endif

	PlatformInitialize(iPad,startIndex);
}

int	IUIScene_AbstractContainerMenu::GetSectionDimensions( ESceneSection eSection, int* piNumColumns, int* piNumRows )
{
	if(IsSectionSlotList(eSection))
	{
		*piNumRows = getSectionRows( eSection );
		*piNumColumns = getSectionColumns( eSection );
	}
	else
	{
		*piNumRows = 0;
		*piNumColumns = 0;
	}
	return( ( *piNumRows ) * ( *piNumColumns ) ); 
}

void IUIScene_AbstractContainerMenu::updateSlotPosition( ESceneSection eSection, ESceneSection newSection, ETapState eTapDirection, int *piTargetX, int *piTargetY, int xOffset )
{
	// Update the target slot based on the size of the current section
	int columns, rows;

	// The return value of this function is unused, but the output params are required.
	//int iItemsNum = GetSectionDimensions( newSection, &columns, &rows );
	GetSectionDimensions( newSection, &columns, &rows );

	if( newSection != eSection )
	{
		// Update Y
		if(eTapDirection == eTapStateUp)
		{
			(*piTargetY) = rows - 1;
		}
		else if(eTapDirection == eTapStateDown)
		{
			(*piTargetY) = 0;
		}
		if( (*piTargetY) < 0 )
		{
			(*piTargetY) = 0;
		}

		// Update X
		int offsetX = (*piTargetX) - xOffset;
		if( offsetX < 0 )
		{
			*piTargetX = 0;
		}
		else if (offsetX >= columns)
		{
			*piTargetX = columns - 1;
		}
		else
		{
			*piTargetX = offsetX;
		}
	}
	else
	{
		// Update X
		int offsetX = (*piTargetX) - xOffset;
		if( offsetX < 0 )
		{
			*piTargetX = columns - 1;
		}
		else if (offsetX >= columns)
		{
			*piTargetX = 0;
		}
		else
		{
			*piTargetX = offsetX;
		}
	}
}

#ifdef TAP_DETECTION
IUIScene_AbstractContainerMenu::ETapState IUIScene_AbstractContainerMenu::GetTapInputType( float fInputX, float fInputY )
{
	if ( ( fabs( fInputX ) < 0.3f ) && ( fabs( fInputY ) < 0.3f ) )
	{
		return eTapStateNoInput;
	}
	else if ( ( fInputX < -0.3f ) && ( fabs( fInputY ) < 0.3f ) )
	{
		return eTapStateLeft;
	}
	else if ( ( fInputX > 0.3f ) && ( fabs( fInputY ) < 0.3f ) )
	{
		return eTapStateRight;
	}
	else if ( ( fInputY < -0.3f ) && ( fabs( fInputX ) < 0.3f ) )
	{
		return eTapStateDown;
	}
	else if ( ( fInputY > 0.3f ) && ( fabs( fInputX ) < 0.3f ) )
	{
		return eTapStateUp;
	}
	else
	{
		return eTapNone;
	}
}
#endif // TAP_DETECTION

void IUIScene_AbstractContainerMenu::SetToolTip( EToolTipButton eButton, EToolTipItem eItem )
{
	if ( m_aeToolTipSettings[ eButton ] != eItem )
	{
		m_aeToolTipSettings[ eButton ] = eItem;
		UpdateTooltips();
	}
}

void IUIScene_AbstractContainerMenu::UpdateTooltips()
{
	// Table gives us text id for tooltip.
	static const DWORD kaToolTipextIds[ eNumToolTips ] = 
	{
		IDS_TOOLTIPS_PICKUPPLACE,			//eToolTipPickupPlace_OLD
		IDS_TOOLTIPS_EXIT,					// eToolTipExit
		IDS_TOOLTIPS_PICKUP_GENERIC,		// eToolTipPickUpGeneric
		IDS_TOOLTIPS_PICKUP_ALL,			// eToolTipPickUpAll
		IDS_TOOLTIPS_PICKUP_HALF,			// eToolTipPickUpHalf
		IDS_TOOLTIPS_PLACE_GENERIC,			// eToolTipPlaceGeneric
		IDS_TOOLTIPS_PLACE_ONE,				// eToolTipPlaceOne
		IDS_TOOLTIPS_PLACE_ALL,				// eToolTipPlaceAll
		IDS_TOOLTIPS_DROP_GENERIC,			// eToolTipDropGeneric
		IDS_TOOLTIPS_DROP_ONE,				// eToolTipDropOne
		IDS_TOOLTIPS_DROP_ALL,				// eToolTipDropAll
		IDS_TOOLTIPS_SWAP,					// eToolTipSwap
		IDS_TOOLTIPS_QUICK_MOVE,			// eToolTipQuickMove
		IDS_TOOLTIPS_QUICK_MOVE_INGREDIENT,	// eToolTipQuickMoveIngredient
		IDS_TOOLTIPS_QUICK_MOVE_FUEL,		// eToolTipQuickMoveTool
		IDS_TOOLTIPS_WHAT_IS_THIS,			// eToolTipWhatIsThis
		IDS_TOOLTIPS_EQUIP,					// eToolTipEquip
		IDS_TOOLTIPS_CLEAR_QUICK_SELECT,	// eToolTipClearQuickSelect
		IDS_TOOLTIPS_QUICK_MOVE_TOOL,		// eToolTipQuickMoveTool
		IDS_TOOLTIPS_QUICK_MOVE_ARMOR,		// eToolTipQuickMoveTool
		IDS_TOOLTIPS_QUICK_MOVE_WEAPON,		// eToolTipQuickMoveTool
		IDS_TOOLTIPS_DYE,					// eToolTipDye
		IDS_TOOLTIPS_REPAIR,				// eToolTipRepair
	};

	BYTE focusUser = getPad();

	for ( int i = 0; i < eToolTipNumButtons; ++i )
	{
		if ( m_aeToolTipSettings[ i ] == eToolTipNone )
		{
			ui.ShowTooltip( focusUser, i, FALSE );
		}
		else
		{
			ui.SetTooltipText( focusUser, i, kaToolTipextIds[ m_aeToolTipSettings[ i ] ] );
			ui.ShowTooltip( focusUser, i, TRUE );
		}
	}
}

void IUIScene_AbstractContainerMenu::onMouseTick()
{
	Minecraft *pMinecraft = Minecraft::GetInstance();
	if( pMinecraft->localgameModes[getPad()] != NULL)
	{
		Tutorial *tutorial = pMinecraft->localgameModes[getPad()]->getTutorial();
		if(tutorial != NULL)
		{
			if(ui.IsTutorialVisible(getPad()) && !tutorial->isInputAllowed(ACTION_MENU_UP))
			{
				return;
			}
		}
	}

	// Offset to display carried item attached to pointer.
	// 	static const float kfCarriedItemOffsetX = -5.0f;
	// 	static const float kfCarriedItemOffsetY = -5.0f;
	float fInputDirX=0.0f;
	float fInputDirY=0.0f;

	// Get current pointer position.
	UIVec2D vPointerPos = m_pointerPos;

	// Offset to image centre.
	vPointerPos.x += m_fPointerImageOffsetX;
	vPointerPos.y += m_fPointerImageOffsetY;

	// Get stick input.
	int iPad = getPad();

	bool bStickInput = false;
	float fInputX = InputManager.GetJoypadStick_LX( iPad, false )*((float)app.GetGameSettings(iPad,eGameSetting_Sensitivity_InMenu)/100.0f); // apply the sensitivity
	float fInputY = InputManager.GetJoypadStick_LY( iPad, false )*((float)app.GetGameSettings(iPad,eGameSetting_Sensitivity_InMenu)/100.0f); // apply the sensitivity

#ifdef __ORBIS__
	// should have sensitivity for the touchpad
	//(float)app.GetGameSettings(iPad,eGameSetting_Sensitivity_TouchPadInMenu)/100.0f

	// get the touchpad input and treat it as a map to the window
	ScePadTouchData *pTouchPadData=InputManager.GetTouchPadData(iPad);

	// make sure the touchpad button isn't down (it's the pausemenu)

	if((!InputManager.ButtonDown(iPad, ACTION_MENU_TOUCHPAD_PRESS)) && (pTouchPadData->touchNum>0))
	{
		if(m_bFirstTouchStored[iPad]==false)
		{
			m_oldvTouchPos.x=(float)pTouchPadData->touch[0].x;
			m_oldvTouchPos.y=(float)pTouchPadData->touch[0].y;
			m_oldvPointerPos.x=vPointerPos.x;
			m_oldvPointerPos.y=vPointerPos.y;
			m_bFirstTouchStored[iPad]=true;
		}

		// should take the average of multiple touch points

		float fNewX=(((float)pTouchPadData->touch[0].x)-m_oldvTouchPos.x) * m_fTouchPadMulX;
		float fNewY=(((float)pTouchPadData->touch[0].y)-m_oldvTouchPos.y) * m_fTouchPadMulY;
		// relative positions - needs a deadzone 

		if(fNewX>m_fTouchPadDeadZoneX)
		{
			vPointerPos.x=m_oldvPointerPos.x+((fNewX-m_fTouchPadDeadZoneX)*((float)app.GetGameSettings(iPad,eGameSetting_Sensitivity_InMenu)/100.0f));
		}
		else if(fNewX<-m_fTouchPadDeadZoneX)
		{
			vPointerPos.x=m_oldvPointerPos.x+((fNewX+m_fTouchPadDeadZoneX)*((float)app.GetGameSettings(iPad,eGameSetting_Sensitivity_InMenu)/100.0f));
		}

		if(fNewY>m_fTouchPadDeadZoneY)
		{
			vPointerPos.y=m_oldvPointerPos.y+((fNewY-m_fTouchPadDeadZoneY)*((float)app.GetGameSettings(iPad,eGameSetting_Sensitivity_InMenu)/100.0f));		
		}
		else if(fNewY<-m_fTouchPadDeadZoneY)
		{
			vPointerPos.y=m_oldvPointerPos.y+((fNewY+m_fTouchPadDeadZoneY)*((float)app.GetGameSettings(iPad,eGameSetting_Sensitivity_InMenu)/100.0f));		
		}

		// Clamp to pointer extents.
		if ( vPointerPos.x < m_fPointerMinX )				vPointerPos.x = m_fPointerMinX;
		else if ( vPointerPos.x > m_fPointerMaxX )			vPointerPos.x = m_fPointerMaxX;
		if ( vPointerPos.y < m_fPointerMinY )				vPointerPos.y = m_fPointerMinY;
		else if ( vPointerPos.y > m_fPointerMaxY )			vPointerPos.y = m_fPointerMaxY;

		bStickInput = true;
		m_eCurrTapState=eTapStateNoInput;	
	}
	else
	{
		// reset the touch flag
		m_bFirstTouchStored[iPad]=false;

#endif



		// If there is any input on sticks, move the pointer.
		if ( ( fabs( fInputX ) >= 0.01f ) || ( fabs( fInputY ) >= 0.01f ) )
		{
			fInputDirX = ( fInputX > 0.0f ) ? 1.0f : ( fInputX < 0.0f )?-1.0f : 0.0f;
			fInputDirY = ( fInputY > 0.0f ) ? 1.0f : ( fInputY < 0.0f )?-1.0f : 0.0f;

#ifdef TAP_DETECTION
			// Check for potential tap input to jump slot.
			ETapState eNewTapInput = GetTapInputType( fInputX, fInputY );

			switch( m_eCurrTapState )
			{
			case eTapStateNoInput:
				m_eCurrTapState = eNewTapInput;
				break;

			case eTapStateUp:
			case eTapStateDown:
			case eTapStateLeft:
			case eTapStateRight:
				if ( ( eNewTapInput != m_eCurrTapState ) && ( eNewTapInput != eTapStateNoInput ) )
				{
					// Input is no longer suitable for tap.
					m_eCurrTapState = eTapNone;
				}
				break;

			case eTapNone:
				/// Nothing to do, input is not a tap.
				break;
			}
#endif // TAP_DETECTION

			// Square it so we get more precision for small inputs.
			fInputX = fInputX * fInputX * fInputDirX * POINTER_SPEED_FACTOR;
			fInputY = fInputY * fInputY * fInputDirY * POINTER_SPEED_FACTOR;
			//fInputX = fInputX * POINTER_SPEED_FACTOR;
			//fInputY = fInputY * POINTER_SPEED_FACTOR;
			float fInputScale = 1.0f;

			// Ramp up input from zero when new input is recieved over INPUT_TICKS_FOR_SCALING ticks. This is to try to improve tapping stick to move 1 box.
			if ( m_iConsectiveInputTicks < MAX_INPUT_TICKS_FOR_SCALING )
			{
				++m_iConsectiveInputTicks;
				fInputScale = ( (float)( m_iConsectiveInputTicks) / (float)(MAX_INPUT_TICKS_FOR_SCALING) );
			}
#ifdef TAP_DETECTION
			else if ( m_iConsectiveInputTicks < MAX_INPUT_TICKS_FOR_TAPPING )
			{
				++m_iConsectiveInputTicks;
			}
			else
			{
				m_eCurrTapState = eTapNone;
			}
#endif
			// 4J Stu - The cursor moves too fast in SD mode
			// The SD/splitscreen scenes are approximately 0.6 times the size of the fullscreen on
			if(!RenderManager.IsHiDef() || app.GetLocalPlayerCount() > 1) fInputScale *= 0.6f;

			fInputX *= fInputScale;
			fInputY *= fInputScale;

#ifdef USE_POINTER_ACCEL		
			m_fPointerAccelX += fInputX / 50.0f;
			m_fPointerAccelY += fInputY / 50.0f;

			if ( fabsf( fInputX ) > fabsf( m_fPointerVelX + m_fPointerAccelX ) )
			{
				m_fPointerVelX += m_fPointerAccelX;
			}
			else
			{
				m_fPointerAccelX = fInputX - m_fPointerVelX;
				m_fPointerVelX = fInputX;
			}

			if ( fabsf( fInputY ) > fabsf( m_fPointerVelY + m_fPointerAccelY ) )
			{
				m_fPointerVelY += m_fPointerAccelY;
			}
			else
			{
				m_fPointerAccelY = fInputY - m_fPointerVelY;
				m_fPointerVelY = fInputY;
			}
			//printf( "IN %.2f  VEL %.2f  ACC %.2f\n", fInputY, m_fPointerVelY, m_fPointerAccelY );

			vPointerPos.x += m_fPointerVelX;
			vPointerPos.y -= m_fPointerVelY;
#else
			// Add input to pointer position.
			vPointerPos.x += fInputX;
			vPointerPos.y -= fInputY;
#endif
			// Clamp to pointer extents.
			if ( vPointerPos.x < m_fPointerMinX )				vPointerPos.x = m_fPointerMinX;
			else if ( vPointerPos.x > m_fPointerMaxX )		vPointerPos.x = m_fPointerMaxX;
			if ( vPointerPos.y < m_fPointerMinY )				vPointerPos.y = m_fPointerMinY;
			else if ( vPointerPos.y > m_fPointerMaxY )		vPointerPos.y = m_fPointerMaxY;

			bStickInput = true;
		}
		else
		{
			m_iConsectiveInputTicks = 0;
#ifdef USE_POINTER_ACCEL	
			m_fPointerVelX = 0.0f;
			m_fPointerVelY = 0.0f;
			m_fPointerAccelX = 0.0f;
			m_fPointerAccelY = 0.0f;
#endif		
		}

#ifdef __ORBIS__
	}
#endif

#ifdef _WINDOWS64
	if (!g_KBMInput.IsMouseGrabbed())
	{
		int dx = g_KBMInput.GetMouseDeltaX();
		int dy = g_KBMInput.GetMouseDeltaY();
		if (dx != 0 || dy != 0)
		{
			float sensitivity = (float)app.GetGameSettings(iPad, eGameSetting_Sensitivity_InMenu) / 100.0f;
			float mouseScale = sensitivity * 1.0f;
			vPointerPos.x += (float)dx * mouseScale;
			vPointerPos.y += (float)dy * mouseScale;
			
			if (vPointerPos.x < m_fPointerMinX) vPointerPos.x = m_fPointerMinX;
			else if (vPointerPos.x > m_fPointerMaxX) vPointerPos.x = m_fPointerMaxX;
			if (vPointerPos.y < m_fPointerMinY) vPointerPos.y = m_fPointerMinY;
			else if (vPointerPos.y > m_fPointerMaxY) vPointerPos.y = m_fPointerMaxY;

			bStickInput = true;
		}
	}
#endif

	// Determine which slot the pointer is currently over.
	ESceneSection eSectionUnderPointer = eSectionNone;
	int iNewSlotX = -1;
	int iNewSlotY = -1;
	int iNewSlotIndex = -1;
	bool bPointerIsOverSlot = false;

	// Centre position of item under pointer, use this to snap pointer to item.
	D3DXVECTOR3 vSnapPos;

	for ( int iSection = m_eFirstSection; iSection < m_eMaxSection; ++iSection )
	{
		// Do not check any further if we have already found the item under the pointer.
		if(m_eCurrTapState == eTapStateJump)
		{
			eSectionUnderPointer = m_eCurrSection;
		}
		else if ( eSectionUnderPointer == eSectionNone )
		{
			ESceneSection eSection = ( ESceneSection )( iSection );

			// Get position of this section.
			UIVec2D sectionPos;
			GetPositionOfSection( eSection, &( sectionPos ) );

			if(!IsSectionSlotList(eSection))
			{
				UIVec2D itemPos;
				UIVec2D itemSize;
				GetItemScreenData( eSection, 0, &( itemPos ), &( itemSize ) );

				UIVec2D itemMax = itemSize;
				itemMax += itemPos;

				if ( ( vPointerPos.x >= sectionPos.x ) && ( vPointerPos.x <= itemMax.x ) &&
					( vPointerPos.y >= sectionPos.y ) && ( vPointerPos.y <= itemMax.y ) )
				{
					// Pointer is over this control!
					eSectionUnderPointer = eSection;						

					vSnapPos.x = itemPos.x + ( itemSize.x / 2.0f );
					vSnapPos.y = itemPos.y + ( itemSize.y / 2.0f );

					// Does this section already have focus.
					if ( !doesSectionTreeHaveFocus( eSection ) )
					{
						// Give focus to this section.
						setSectionFocus(eSection, getPad());
					}

					bPointerIsOverSlot = false;

					// Have we actually changed slot? If so, input cannot be a tap.
					if ( ( eSectionUnderPointer != m_eCurrSection ) || ( iNewSlotX != m_iCurrSlotX ) || ( iNewSlotY != m_iCurrSlotY ) )
					{
						m_eCurrTapState = eTapNone;
					}

					// Store what is currently under the pointer.
					m_eCurrSection = eSectionUnderPointer;
				}
			}
			else
			{

				// Get dimensions of this section.
				int iNumRows;
				int iNumColumns;
				int iNumItems = GetSectionDimensions( eSection, &( iNumColumns ), &( iNumRows ) );

				// Check each item to see if pointer is over it.
				for ( int iItem = 0; iItem < iNumItems; ++iItem )
				{
					UIVec2D itemPos;
					UIVec2D itemSize;
					GetItemScreenData( eSection, iItem, &( itemPos ), &( itemSize ) );

					itemPos += sectionPos;

					UIVec2D itemMax = itemSize;
					itemMax += itemPos;

					if ( ( vPointerPos.x >= itemPos.x ) && ( vPointerPos.x <= itemMax.x ) &&
						( vPointerPos.y >= itemPos.y ) && ( vPointerPos.y <= itemMax.y ) )
					{
						// Pointer is over this slot!
						eSectionUnderPointer = eSection;
						iNewSlotIndex = iItem;
						iNewSlotX = iNewSlotIndex % iNumColumns;
						iNewSlotY = iNewSlotIndex / iNumColumns;

						vSnapPos.x = itemPos.x + ( itemSize.x / 2.0f );
						vSnapPos.y = itemPos.y + ( itemSize.y / 2.0f );

						// Does this section already have focus.
						if ( !doesSectionTreeHaveFocus( eSection ) )
						{
							// Give focus to this section.
							setSectionFocus(eSection, getPad());
						}

						// Set the highlight marker.
						setSectionSelectedSlot(eSection, iNewSlotX, iNewSlotY );

						bPointerIsOverSlot = true;

#ifdef TAP_DETECTION
						// Have we actually changed slot? If so, input cannot be a tap.
						if ( ( eSectionUnderPointer != m_eCurrSection ) || ( iNewSlotX != m_iCurrSlotX ) || ( iNewSlotY != m_iCurrSlotY ) )
						{
							m_eCurrTapState = eTapNone;
						}

						// Store what is currently under the pointer.
						m_eCurrSection = eSectionUnderPointer;
						m_iCurrSlotX = iNewSlotX;
						m_iCurrSlotY = iNewSlotY;
#endif // TAP_DETECTION
						// No need to check any further slots, the pointer can only ever be over one.
						break;
					}
				}
			}
		}
	}

	// If we are not over any slot, set focus elsewhere.
	if ( eSectionUnderPointer == eSectionNone ) 
	{
		setFocusToPointer( getPad() );
#ifdef TAP_DETECTION
		// Input cannot be a tap.
		m_eCurrTapState = eTapNone;

		// Store what is currently under the pointer.
		m_eCurrSection = eSectionNone;
		m_iCurrSlotX = -1;
		m_iCurrSlotY = -1;
#endif // TAP_DETECTION
	}
	else
	{
		if ( !bStickInput )
		{
			// Did we get a tap input?
			int iDesiredSlotX = -1;
			int iDesiredSlotY = -1;

			switch( m_eCurrTapState )
			{
			case eTapStateUp:
				iDesiredSlotX = m_iCurrSlotX;
				iDesiredSlotY = m_iCurrSlotY - 1;
				break;
			case eTapStateDown:
				iDesiredSlotX = m_iCurrSlotX;
				iDesiredSlotY = m_iCurrSlotY + 1;
				break;
			case eTapStateLeft:
				iDesiredSlotX = m_iCurrSlotX - 1;
				iDesiredSlotY = m_iCurrSlotY;
				break;
			case eTapStateRight:
				iDesiredSlotX = m_iCurrSlotX + 1;
				iDesiredSlotY = m_iCurrSlotY;
				break;
			case eTapStateJump:
				iDesiredSlotX = m_iCurrSlotX;
				iDesiredSlotY = m_iCurrSlotY;
				break;
			}

			int iNumRows;
			int iNumColumns;
			int iNumItems = GetSectionDimensions( eSectionUnderPointer, &( iNumColumns ), &( iNumRows ) );


			if ( (m_eCurrTapState != eTapNone && m_eCurrTapState != eTapStateNoInput) &&
				( !IsSectionSlotList(eSectionUnderPointer) ||
				( ( iDesiredSlotX < 0 ) || ( iDesiredSlotX >= iNumColumns ) || ( iDesiredSlotY < 0 ) || ( iDesiredSlotY >= iNumRows ) )
				))
			{

				eSectionUnderPointer = GetSectionAndSlotInDirection( eSectionUnderPointer, m_eCurrTapState, &iDesiredSlotX, &iDesiredSlotY );

				if(!IsSectionSlotList(eSectionUnderPointer)) bPointerIsOverSlot = false;

				// Get the details for the new section
				iNumItems = GetSectionDimensions( eSectionUnderPointer, &( iNumColumns ), &( iNumRows ) );
			}

			if ( !IsSectionSlotList(eSectionUnderPointer) || ( ( iDesiredSlotX >= 0 ) && ( iDesiredSlotX < iNumColumns ) && ( iDesiredSlotY >= 0 ) && ( iDesiredSlotY < iNumRows ) ) )
			{
				// Desired slot after tap input is valid, so make the jump to this slot.
				UIVec2D sectionPos;
				GetPositionOfSection( eSectionUnderPointer, &( sectionPos ) );

				iNewSlotIndex = ( iDesiredSlotY * iNumColumns ) + iDesiredSlotX;

				UIVec2D itemPos;
				UIVec2D itemSize;
				GetItemScreenData( eSectionUnderPointer, iNewSlotIndex, &( itemPos ), &( itemSize ) );

				if(IsSectionSlotList(eSectionUnderPointer)) itemPos += sectionPos;

				vSnapPos.x = itemPos.x + ( itemSize.x / 2.0f);
				vSnapPos.y = itemPos.y + ( itemSize.y / 2.0f);

				m_eCurrSection = eSectionUnderPointer;
				m_iCurrSlotX = iDesiredSlotX;
				m_iCurrSlotY = iDesiredSlotY;
			}

			m_eCurrTapState = eTapStateNoInput;

			// If there is no stick input, and we are over a slot, then snap pointer to slot centre.
			// 4J - TomK - only if this particular component allows so!
			if(CanHaveFocus(eSectionUnderPointer))
			{
				vPointerPos.x = vSnapPos.x;
				vPointerPos.y = vSnapPos.y;
			}
		}
	}

	// Clamp to pointer extents.
	if ( vPointerPos.x < m_fPointerMinX )				vPointerPos.x = m_fPointerMinX;
	else if ( vPointerPos.x > m_fPointerMaxX )		vPointerPos.x = m_fPointerMaxX;
	if ( vPointerPos.y < m_fPointerMinY )				vPointerPos.y = m_fPointerMinY;
	else if ( vPointerPos.y > m_fPointerMaxY )		vPointerPos.y = m_fPointerMaxY;

	// Check if the pointer is outside of the panel.
	bool bPointerIsOutsidePanel = false;
	if ( ( vPointerPos.x < m_fPanelMinX ) || ( vPointerPos.x > m_fPanelMaxX ) || ( vPointerPos.y < m_fPanelMinY ) || ( vPointerPos.y > m_fPanelMaxY ) )
	{
		bPointerIsOutsidePanel = true;
	}

	// Determine appropriate context sensitive tool tips, based on what is carried on the pointer and what is under the pointer.

	// What are we carrying on pointer.
	shared_ptr<LocalPlayer> player = Minecraft::GetInstance()->localplayers[getPad()];
	shared_ptr<ItemInstance> carriedItem = nullptr;
	if(player != NULL) carriedItem = player->inventory->getCarried();

	shared_ptr<ItemInstance> slotItem = nullptr;
	Slot *slot = NULL;
	int slotIndex = 0;
	if(bPointerIsOverSlot)
	{
		slotIndex = iNewSlotIndex + getSectionStartOffset( eSectionUnderPointer );
		slot = m_menu->getSlot(slotIndex);
	}
	bool bIsItemCarried = carriedItem != NULL;
	int iCarriedCount = 0;
	bool bCarriedIsSameAsSlot = false;	// Indicates if same item is carried on pointer as is in slot under pointer.
	if ( bIsItemCarried )
	{
		iCarriedCount = carriedItem->count;
	}

	// What is in the slot that we are over.
	bool bSlotHasItem = false;
	bool bMayPlace = false;
	bool bCanPlaceOne = false;
	bool bCanPlaceAll = false;
	bool bCanCombine = false;
	bool bCanDye = false;
	int iSlotCount = 0;
	int iSlotStackSizeRemaining = 0;	// How many more items can be stacked on this slot.
	if ( bPointerIsOverSlot )
	{
		slotItem = slot->getItem();
		bSlotHasItem = slotItem != NULL;
		if ( bSlotHasItem )
		{
			iSlotCount = slotItem->GetCount();

			if ( bIsItemCarried )
			{
				bCarriedIsSameAsSlot = IsSameItemAs(carriedItem, slotItem);
				bCanCombine = m_menu->mayCombine(slot,carriedItem);
				bCanDye = bCanCombine && dynamic_cast<ArmorItem *>(slot->getItem()->getItem());

				if ( bCarriedIsSameAsSlot )
				{
					iSlotStackSizeRemaining = GetEmptyStackSpace( m_menu->getSlot(slotIndex) );
				}
			}
		}

		if( bIsItemCarried)
		{
			bMayPlace = slot->mayPlace(carriedItem);

			if ( bSlotHasItem ) iSlotStackSizeRemaining = GetEmptyStackSpace( slot );
			else iSlotStackSizeRemaining = slot->getMaxStackSize();

			if(bMayPlace && iSlotStackSizeRemaining > 0) bCanPlaceOne = true;
			if(bMayPlace && iSlotStackSizeRemaining > 1 && carriedItem->count > 1) bCanPlaceAll = true;
		}
	}

	if( bPointerIsOverSlot && bSlotHasItem )
	{
		vector<wstring> unformattedStrings;
		wstring desc = GetItemDescription( slot, unformattedStrings );
		SetPointerText(desc, unformattedStrings, slot != m_lastPointerLabelSlot);
		m_lastPointerLabelSlot = slot;
	}
	else
	{
		vector<wstring> unformattedStrings;
		SetPointerText(L"", unformattedStrings, false);
		m_lastPointerLabelSlot = NULL;
	}

	EToolTipItem buttonA, buttonX, buttonY, buttonRT;
	buttonA = buttonX = buttonY = buttonRT = eToolTipNone;
	if ( bPointerIsOverSlot )
	{
		SetPointerOutsideMenu( false );
		if ( bIsItemCarried )
		{
			if ( bSlotHasItem )
			{
				// Item in hand and item in slot ... is item in slot the same as in out hand? If so, can we stack on to it?
				if ( bCarriedIsSameAsSlot ) 
				{
					// Can we stack more into this slot?
					if ( iSlotStackSizeRemaining == 0 )
					{
						// Cannot stack any more.
						buttonRT = eToolTipWhatIsThis;
					}
					else if ( iSlotStackSizeRemaining == 1 )
					{
						// Can only put 1 more on the stack.
						buttonA = eToolTipPlaceGeneric;
						buttonRT = eToolTipWhatIsThis;
					}
					else // can put 1 or all.
					{
						if(bCanPlaceAll)
						{
							// Multiple items in hand.
							buttonA = eToolTipPlaceAll;
							buttonX = eToolTipPlaceOne;
						}
						else if(bCanPlaceOne)
						{
							if(iCarriedCount > 1) buttonA = eToolTipPlaceOne;
							else buttonA = eToolTipPlaceGeneric;
						}
						buttonRT = eToolTipWhatIsThis;
					}
				}
				else // items are different, click here will swap them.
				{

					if(bMayPlace) buttonA = eToolTipSwap;
					buttonRT = eToolTipWhatIsThis;
				}
				if(bCanDye)
				{
					buttonX = eToolTipDye;
				}
				else if(bCanCombine)
				{
					buttonX = eToolTipRepair;
				}
			}
			else // slot empty.
			{
				// Item in hand, slot is empty.
				if ( iCarriedCount == 1 )
				{
					// Only one item in hand.
					buttonA = eToolTipPlaceGeneric;
				}
				else
				{
					if(bCanPlaceAll)
					{
						// Multiple items in hand.
						buttonA = eToolTipPlaceAll;
						buttonX = eToolTipPlaceOne;
					}
					else if(bCanPlaceOne)
					{
						buttonA = eToolTipPlaceOne;
					}
				}
			}
		}
		else // no object in hand
		{
			if ( bSlotHasItem )
			{
				if ( iSlotCount == 1 )
				{
					buttonA = eToolTipPickUpGeneric;
					buttonRT = eToolTipWhatIsThis;
				}
				else
				{
					// Multiple items in slot.
					buttonA = eToolTipPickUpAll;
					buttonX = eToolTipPickUpHalf;
					buttonRT = eToolTipWhatIsThis;
				}
			}
			else
			{
				// Nothing in slot and nothing in hand.
			}
		}

		if ( bSlotHasItem )
		{
			// Item in slot

			// 4J-PB - show tooltips for quick use of armour

			if((eSectionUnderPointer==eSectionInventoryUsing)||(eSectionUnderPointer==eSectionInventoryInventory))
			{
				shared_ptr<ItemInstance> item = getSlotItem(eSectionUnderPointer, iNewSlotIndex);
				ArmorRecipes::_eArmorType eArmourType=ArmorRecipes::GetArmorType(item->id);

				if(eArmourType==ArmorRecipes::eArmorType_None)
				{
					buttonY = eToolTipQuickMove;
				}
				else
				{
					// check that the slot required is empty
					switch(eArmourType)
					{
					case ArmorRecipes::eArmorType_Helmet:
						if(isSlotEmpty(eSectionInventoryArmor,0))
						{
							buttonY = eToolTipEquip;
						}
						else
						{
							buttonY = eToolTipQuickMove;
						}
						break;
					case ArmorRecipes::eArmorType_Chestplate:
						if(isSlotEmpty(eSectionInventoryArmor,1))
						{
							buttonY = eToolTipEquip;
						}
						else
						{
							buttonY = eToolTipQuickMove;
						}								
						break;
					case ArmorRecipes::eArmorType_Leggings:
						if(isSlotEmpty(eSectionInventoryArmor,2))
						{
							buttonY = eToolTipEquip;
						}
						else
						{
							buttonY = eToolTipQuickMove;
						}
						break;
					case ArmorRecipes::eArmorType_Boots:
						if(isSlotEmpty(eSectionInventoryArmor,3))
						{
							buttonY = eToolTipEquip;
						}
						else
						{
							buttonY = eToolTipQuickMove;
						}
						break;
					default:
						buttonY = eToolTipQuickMove;
						break;
					}

				}
			}
			// 4J-PB - show tooltips for quick use of fuel or ingredient
			else if((eSectionUnderPointer==eSectionFurnaceUsing)||(eSectionUnderPointer==eSectionFurnaceInventory))
			{
				// Get the info on this item.
				shared_ptr<ItemInstance> item = getSlotItem(eSectionUnderPointer, iNewSlotIndex);
				bool bValidFuel = FurnaceTileEntity::isFuel(item);
				bool bValidIngredient = FurnaceRecipes::getInstance()->getResult(item->getItem()->id) != NULL;

				if(bValidIngredient)
				{
					// is there already something in the ingredient slot?
					if(!isSlotEmpty(eSectionFurnaceIngredient,0))
					{
						// is it the same as this item
						shared_ptr<ItemInstance> IngredientItem = getSlotItem(eSectionFurnaceIngredient,0);
						if(IngredientItem->id == item->id)
						{
							buttonY = eToolTipQuickMoveIngredient;
						}
						else
						{
							if(FurnaceRecipes::getInstance()->getResult(item->id)==NULL)
							{
								buttonY = eToolTipQuickMove;
							}
							else
							{
								buttonY = eToolTipQuickMoveIngredient;
							}
						}
					}
					else
					{
						// ingredient slot empty
						buttonY = eToolTipQuickMoveIngredient;
					}
				}
				else if(bValidFuel)
				{
					// Is there already something in the fuel slot?
					if(!isSlotEmpty(eSectionFurnaceFuel,0))
					{
						// is it the same as this item
						shared_ptr<ItemInstance> fuelItem = getSlotItem(eSectionFurnaceFuel,0);
						if(fuelItem->id == item->id)
						{
							buttonY = eToolTipQuickMoveFuel;
						}
						else if(bValidIngredient)
						{
							// check if the ingredient slot is empty, or the same as this
							if(!isSlotEmpty(eSectionFurnaceIngredient,0))
							{
								// is it the same as this item
								shared_ptr<ItemInstance> IngredientItem = getSlotItem(eSectionFurnaceIngredient,0);
								if(IngredientItem->id == item->id)
								{
									buttonY = eToolTipQuickMoveIngredient;
								}
								else
								{
									if(FurnaceRecipes::getInstance()->getResult(item->id)==NULL)
									{
										buttonY = eToolTipQuickMove;
									}
									else
									{
										buttonY = eToolTipQuickMoveIngredient;
									}
								}
							}
							else
							{
								// ingredient slot empty
								buttonY = eToolTipQuickMoveIngredient;
							}
						}
						else
						{
							buttonY = eToolTipQuickMove;
						}
					}
					else
					{
						buttonY = eToolTipQuickMoveFuel;
					}
				}
				else
				{
					buttonY = eToolTipQuickMove;
				}
			}
			// 4J-PB - show tooltips for quick use of ingredients in brewing
			else if((eSectionUnderPointer==eSectionBrewingUsing)||(eSectionUnderPointer==eSectionBrewingInventory))
			{
				// Get the info on this item.
				shared_ptr<ItemInstance> item = getSlotItem(eSectionUnderPointer, iNewSlotIndex);
				int iId=item->id;

				// valid ingredient?
				bool bValidIngredient=false;
				//bool bValidIngredientBottom=false;

				if(Item::items[iId]->hasPotionBrewingFormula() || (iId == Item::netherStalkSeeds_Id))
				{
					bValidIngredient=true;
				}

				if(bValidIngredient)
				{
					// is there already something in the ingredient slot?
					if(!isSlotEmpty(eSectionBrewingIngredient,0))
					{
						// is it the same as this item
						shared_ptr<ItemInstance> IngredientItem = getSlotItem(eSectionBrewingIngredient,0);
						if(IngredientItem->id == item->id)
						{
							buttonY = eToolTipQuickMoveIngredient;
						}
						else
						{
							buttonY=eToolTipQuickMove;
						}
					}
					else
					{
						// ingredient slot empty
						buttonY = eToolTipQuickMoveIngredient;
					}
				}						
				else
				{
					// valid potion? Glass bottle with water in it is a 'potion' too.
					if(iId==Item::potion_Id)
					{
						// space available?
						if(isSlotEmpty(eSectionBrewingBottle1,0) || 
							isSlotEmpty(eSectionBrewingBottle2,0) || 
							isSlotEmpty(eSectionBrewingBottle3,0))
						{
							buttonY = eToolTipQuickMoveIngredient;
						}
						else
						{
							buttonY=eToolTipNone;
						}
					}
					else
					{
						buttonY=eToolTipQuickMove;
					}
				}
			}
			else if((eSectionUnderPointer==eSectionEnchantUsing)||(eSectionUnderPointer==eSectionEnchantInventory))
			{
				// Get the info on this item.
				shared_ptr<ItemInstance> item = getSlotItem(eSectionUnderPointer, iNewSlotIndex);
				int iId=item->id;

				// valid enchantable tool?
				if(Item::items[iId]->isEnchantable(item))
				{
					// is there already something in the ingredient slot?
					if(isSlotEmpty(eSectionEnchantSlot,0))
					{					
						// tool slot empty	
						switch(iId)
						{
						case Item::bow_Id:
						case Item::sword_wood_Id:
						case Item::sword_stone_Id:
						case Item::sword_iron_Id:
						case Item::sword_diamond_Id:
							buttonY=eToolTipQuickMoveWeapon;
							break;

						case Item::helmet_cloth_Id:
						case Item::chestplate_cloth_Id:
						case Item::leggings_cloth_Id:
						case Item::boots_cloth_Id:

						case Item::helmet_chain_Id:
						case Item::chestplate_chain_Id:
						case Item::leggings_chain_Id:
						case Item::boots_chain_Id:

						case Item::helmet_iron_Id:
						case Item::chestplate_iron_Id:
						case Item::leggings_iron_Id:
						case Item::boots_iron_Id:

						case Item::helmet_diamond_Id:
						case Item::chestplate_diamond_Id:
						case Item::leggings_diamond_Id:
						case Item::boots_diamond_Id:

						case Item::helmet_gold_Id:
						case Item::chestplate_gold_Id:
						case Item::leggings_gold_Id:
						case Item::boots_gold_Id:
							buttonY=eToolTipQuickMoveArmor;

							break;
						case Item::book_Id:
							buttonY = eToolTipQuickMove;
							break;
						default:
							buttonY=eToolTipQuickMoveTool;									
							break;
						}
					}
					else
					{
						buttonY = eToolTipQuickMove;
					}
				}						
				else
				{
					buttonY=eToolTipQuickMove;							
				}
			}
			else
			{
				buttonY = eToolTipQuickMove;
			}
		}
	}

	if ( bPointerIsOutsidePanel )
	{
		SetPointerOutsideMenu( true );
		// Outside window, we dropping items.
		if ( bIsItemCarried )
		{
			//int iCount = m_pointerControl->GetObjectCount( m_pointerControl->m_hObj );
			if ( iCarriedCount > 1 )
			{
				buttonA = eToolTipDropAll;
				buttonX = eToolTipDropOne;
			}
			else
			{
				buttonA = eToolTipDropGeneric;
			}
		}
	}
	else // pointer is just over dead space ... can't really do anything.
	{
		SetPointerOutsideMenu( false );
	}

	shared_ptr<ItemInstance> item = nullptr;
	if(bPointerIsOverSlot && bSlotHasItem) item = getSlotItem(eSectionUnderPointer, iNewSlotIndex);
	overrideTooltips(eSectionUnderPointer, item, bIsItemCarried, bSlotHasItem, bCarriedIsSameAsSlot, iSlotStackSizeRemaining, buttonA, buttonX, buttonY, buttonRT);

	SetToolTip( eToolTipButtonA, buttonA );
	SetToolTip( eToolTipButtonX, buttonX );
	SetToolTip( eToolTipButtonY, buttonY );
	SetToolTip( eToolTipButtonRT, buttonRT );


	// Offset back to image top left.
	vPointerPos.x -= m_fPointerImageOffsetX;
	vPointerPos.y -= m_fPointerImageOffsetY;

	// Update pointer position.
	// 4J-PB - do not allow sub pixel positions or we get broken lines in box edges

	// problem here when sensitivity is low - we'll be moving a sub pixel size, so it'll clamp, and we'll never move. In that case, move 1 pixel
	if(fInputDirX!=0.0f)
	{
		if(fInputDirX==1.0f)
		{
			vPointerPos.x+=0.999999f;
		}
		else
		{
			vPointerPos.x-=0.999999f;
		}
	}

	if(fInputDirY!=0.0f)
	{
		if(fInputDirY==1.0f)
		{
			vPointerPos.y+=0.999999f;
		}
		else
		{
			vPointerPos.y-=0.999999f;
		}
	}

	vPointerPos.x = floor(vPointerPos.x);
	vPointerPos.x += ( (int)vPointerPos.x%2);
	vPointerPos.y = floor(vPointerPos.y);
	vPointerPos.y += ( (int)vPointerPos.y%2);
	m_pointerPos = vPointerPos;

	adjustPointerForSafeZone();
}

bool IUIScene_AbstractContainerMenu::handleKeyDown(int iPad, int iAction, bool bRepeat)
{
	bool bHandled = false;

	Minecraft *pMinecraft = Minecraft::GetInstance();
	if( pMinecraft->localgameModes[getPad()] != NULL )
	{
		Tutorial *tutorial = pMinecraft->localgameModes[getPad()]->getTutorial();
		if(tutorial != NULL)
		{
			tutorial->handleUIInput(iAction);
			if(ui.IsTutorialVisible(getPad()) && !tutorial->isInputAllowed(iAction))
			{
				return S_OK;
			}
		}
	}

#ifdef _XBOX
	ui.AnimateKeyPress(iPad, iAction);
#else
	ui.AnimateKeyPress(iPad, iAction, bRepeat, true, false);
#endif

	int buttonNum=0; // 0 = LeftMouse, 1 = RightMouse
	BOOL quickKeyHeld=FALSE; // Represents shift key on PC

	BOOL validKeyPress = FALSE;
	//BOOL itemEditorKeyPress = FALSE;

	// Ignore input from other players
	//if(pMinecraft->player->GetXboxPad()!=pInputData->UserIndex) return S_OK;

	switch(iAction)
	{
#ifdef _DEBUG_MENUS_ENABLED
#if TO_BE_IMPLEMENTED
	case VK_PAD_RTHUMB_PRESS:
		itemEditorKeyPress = TRUE;
		break;
#endif
#endif
	case ACTION_MENU_A:
#ifdef __ORBIS__
	case ACTION_MENU_TOUCHPAD_PRESS:
#endif
		if(!bRepeat)
		{
			validKeyPress = TRUE;

			// Standard left click
			buttonNum = 0;
			quickKeyHeld = FALSE;
			ui.PlayUISFX(eSFX_Press);
		}
		break;
	case ACTION_MENU_X:
		if(!bRepeat)
		{
			validKeyPress = TRUE;

			// Standard right click
			buttonNum = 1;
			quickKeyHeld = FALSE;
			ui.PlayUISFX(eSFX_Press);
		}
		break;
	case ACTION_MENU_Y:
		if(!bRepeat)
		{
			//bool bIsItemCarried = !m_pointerControl->isEmpty( m_pointerControl->m_hObj );

			// 4J Stu - TU8: Remove this fix, and fix the tooltip display instead as customers liked the feature

			// Fix for #58583 - TU6: Content: UI: The Quick Move button prompt disappears even though it still works
			// No quick move tooltip is shown if something is carried, so disable the action as well
			//if(!bIsItemCarried)
			{
				validKeyPress = TRUE;

				// Shift and left click
				buttonNum = 0;
				quickKeyHeld = TRUE;
				ui.PlayUISFX(eSFX_Press);
			}
		}
		break;
		// 4J Stu - Also enable start to exit the scene. This key is also not constrained by the tutorials.
	case ACTION_MENU_PAUSEMENU:
	case ACTION_MENU_B:
		{

			ui.SetTooltips(iPad, -1);

			// 4J Stu - Fix for #11302 - TCR 001: Network Connectivity: Host crashed after being killed by the client while accessing a chest during burst packet loss.
			// We need to make sure that we call closeContainer() anytime this menu is closed, even if it is forced to close by some other reason (like the player dying)
			// Therefore I have moved this call to the OnDestroy() method to make sure that it always happens.
			//Minecraft::GetInstance()->localplayers[pInputData->UserIndex]->closeContainer();

			// Return to the game. We should really callback to the app here as well
			// to let it know that we have closed the ui incase we need to do things when that happens

			if(m_bNavigateBack)
			{
				ui.NavigateBack(iPad);
			}
			else
			{
				ui.CloseUIScenes(iPad);      
			}

			bHandled = true;
			return S_OK;
		}
		break;
	case ACTION_MENU_LEFT:
		{
			//ui.PlayUISFX(eSFX_Focus);
			m_eCurrTapState = eTapStateLeft;
		}
		break;
	case ACTION_MENU_RIGHT:
		{
			//ui.PlayUISFX(eSFX_Focus);
			m_eCurrTapState = eTapStateRight;
		}
		break;
	case ACTION_MENU_UP:
		{
			//ui.PlayUISFX(eSFX_Focus);
			m_eCurrTapState = eTapStateUp;
		}
		break;
	case ACTION_MENU_DOWN:
		{
			//ui.PlayUISFX(eSFX_Focus);
			m_eCurrTapState = eTapStateDown;
		}
		break;
	case ACTION_MENU_PAGEUP:
		{
			// 4J Stu - Do nothing except stop this being passed anywhere else
			bHandled = true;
		}
		break;
#ifdef __PSVITA__
		//CD - Vita uses select for What's this - key 40
	case MINECRAFT_ACTION_GAME_INFO:
#else
	case ACTION_MENU_PAGEDOWN:
#endif

		{
			if( IsSectionSlotList( m_eCurrSection ) )
			{
				int currentIndex = getCurrentIndex( m_eCurrSection ) - getSectionStartOffset(m_eCurrSection);

				bool bSlotHasItem = !isSlotEmpty(m_eCurrSection, currentIndex);
				if ( bSlotHasItem )
				{
					shared_ptr<ItemInstance> item = getSlotItem(m_eCurrSection, currentIndex);
					if( Minecraft::GetInstance()->localgameModes[iPad] != NULL )
					{
						Tutorial::PopupMessageDetails *message = new Tutorial::PopupMessageDetails;
						message->m_messageId = item->getUseDescriptionId();

						if(Item::items[item->id] != NULL) message->m_titleString = Item::items[item->id]->getHoverName(item);
						message->m_titleId = item->getDescriptionId();

						message->m_icon = item->id;
						message->m_iAuxVal = item->getAuxValue();
						message->m_forceDisplay = true;

						TutorialMode *gameMode = (TutorialMode *)Minecraft::GetInstance()->localgameModes[iPad];
						gameMode->getTutorial()->setMessage(NULL, message);
						ui.PlayUISFX(eSFX_Press);
					}
				}
			}
			bHandled = TRUE;
		}
		break;
	};

	if( validKeyPress == TRUE )
	{
		if(handleValidKeyPress(iPad,buttonNum,quickKeyHeld))
		{
			// Used to allow overriding certain keypresses, so do nothing here
		}
		else
		{
			if( IsSectionSlotList( m_eCurrSection ) )
			{
				handleSlotListClicked(m_eCurrSection,buttonNum,quickKeyHeld);
			}
			else
			{
				// TODO Clicked something else, like for example the craft result. Do something here

				// 4J WESTY : For pointer system we can legally drop items outside of the window panel here, or may press button while
				// pointer is over empty panel space.
				if ( m_bPointerOutsideMenu )
				{
					handleOutsideClicked(iPad, buttonNum, quickKeyHeld);
				}
				else // 
				{
					// over empty space or something else???
					handleOtherClicked(iPad,m_eCurrSection,buttonNum,quickKeyHeld?true:false);
					//assert( FALSE );
				}
			}
		}
		bHandled = true;
	}
#ifdef _DEBUG_MENUS_ENABLED
#if TO_BE_IMPLEMENTED
	else if(itemEditorKeyPress == TRUE)
	{
		HXUIOBJ hFocusObject = GetFocus(pInputData->UserIndex);
		HXUIOBJ hFocusObjectParent;
		XuiElementGetParent( hFocusObject, &hFocusObjectParent );

		HXUICLASS hClassCXuiCtrlSlotList;

		// TODO Define values for these
		hClassCXuiCtrlSlotList = XuiFindClass( L"CXuiCtrlSlotList" );

		// If the press comes from a SlotList, cast it up then send a clicked call to it's menu
		if( XuiIsInstanceOf( hFocusObjectParent, hClassCXuiCtrlSlotList ) )
		{
			CXuiCtrlSlotList* slotList;
			VOID *pObj;
			XuiObjectFromHandle( hFocusObjectParent, &pObj );
			slotList = (CXuiCtrlSlotList *)pObj;

			int currentIndex = slotList->GetCurSel();

			CXuiCtrlSlotItemListItem* pCXuiCtrlSlotItem;
			slotList->GetCXuiCtrlSlotItem( currentIndex, &( pCXuiCtrlSlotItem ) );

			//Minecraft *pMinecraft = Minecraft::GetInstance();

			CScene_DebugItemEditor::ItemEditorInput *initData = new CScene_DebugItemEditor::ItemEditorInput();
			initData->iPad = m_iPad;
			initData->slot = pCXuiCtrlSlotItem->getSlot( pCXuiCtrlSlotItem->m_hObj );
			initData->menu = m_menu;

			// Add timer to poll controller stick input at 60Hz
			HRESULT timerResult = KillTimer( POINTER_INPUT_TIMER_ID );
			assert( timerResult == S_OK );

			app.NavigateToScene(m_iPad,eUIScene_DebugItemEditor,(void *)initData,false,TRUE);
		}
	}
#endif
#endif
	else
	{
		handleAdditionalKeyPress(iAction);
	}

	UpdateTooltips();

	return bHandled;
}

bool IUIScene_AbstractContainerMenu::handleValidKeyPress(int iUserIndex, int buttonNum, BOOL quickKeyHeld)
{
	return false;
}

void IUIScene_AbstractContainerMenu::handleOutsideClicked(int iPad, int buttonNum, BOOL quickKeyHeld)
{
	// Drop items.

	//pMinecraft->localgameModes[m_iPad]->handleInventoryMouseClick(menu->containerId, AbstractContainerMenu::CLICKED_OUTSIDE, buttonNum, quickKeyHeld?true:false, pMinecraft->localplayers[m_iPad] );
	slotClicked(AbstractContainerMenu::CLICKED_OUTSIDE, buttonNum, quickKeyHeld?true:false);
}

void IUIScene_AbstractContainerMenu::handleOtherClicked(int iPad, ESceneSection eSection, int buttonNum, bool quickKey)
{
	// Do nothing
}

void IUIScene_AbstractContainerMenu::handleAdditionalKeyPress(int iAction)
{
	// Do nothing
}

void IUIScene_AbstractContainerMenu::handleSlotListClicked(ESceneSection eSection, int buttonNum, BOOL quickKeyHeld)
{
	int currentIndex = getCurrentIndex(eSection);

	//pMinecraft->localgameModes[m_iPad]->handleInventoryMouseClick(menu->containerId, currentIndex, buttonNum, quickKeyHeld?true:false, pMinecraft->localplayers[m_iPad] );
	slotClicked(currentIndex, buttonNum, quickKeyHeld?true:false);

	handleSectionClick(eSection);
}

void IUIScene_AbstractContainerMenu::slotClicked(int slotId, int buttonNum, bool quickKey)
{
	// 4J Stu - Removed this line as unused
	//if (slot != NULL) slotId = slot->index;

	Minecraft *pMinecraft = Minecraft::GetInstance();
	pMinecraft->localgameModes[getPad()]->handleInventoryMouseClick(m_menu->containerId, slotId, buttonNum, quickKey, pMinecraft->localplayers[getPad()] );
}

int IUIScene_AbstractContainerMenu::getCurrentIndex(ESceneSection eSection)
{
	int rows, columns;
	GetSectionDimensions( eSection, &columns, &rows );
	int currentIndex = (m_iCurrSlotY * columns) + m_iCurrSlotX;

	return currentIndex + getSectionStartOffset(eSection);
}

bool IUIScene_AbstractContainerMenu::IsSameItemAs(shared_ptr<ItemInstance> itemA, shared_ptr<ItemInstance> itemB)
{
	if(itemA == NULL || itemB == NULL) return false;

	bool bStackedByData = itemA->isStackedByData();
	return ( ( itemA->id == itemB->id ) && ( (bStackedByData && itemA->getAuxValue() == itemB->getAuxValue()) || !bStackedByData ) );
}

int IUIScene_AbstractContainerMenu::GetEmptyStackSpace(Slot *slot)
{
	int iResult = 0;

	if(slot != NULL && slot->hasItem())
	{
		shared_ptr<ItemInstance> item = slot->getItem();
		if ( item->isStackable() )
		{
			int iCount = item->GetCount();
			int iMaxStackSize = min(item->getMaxStackSize(), slot->getMaxStackSize() );

			iResult = iMaxStackSize - iCount;

			if(iResult < 0 ) iResult = 0;
		}
	}

	return iResult;
}

wstring IUIScene_AbstractContainerMenu::GetItemDescription(Slot *slot, vector<wstring> &unformattedStrings)
{
	if(slot == NULL) return L"";

	wstring desc = L"";
	vector<wstring> *strings = slot->getItem()->getHoverText(nullptr, false, unformattedStrings);
	bool firstLine = true;
	for(AUTO_VAR(it, strings->begin()); it != strings->end(); ++it)
	{
		wstring thisString = *it;
		if(!firstLine)
		{
			desc.append( L"<br />" );
		}
		else
		{
			firstLine = false;				
			wchar_t formatted[256];
			eMinecraftColour rarityColour = slot->getItem()->getRarity()->color;
			int colour = app.GetHTMLColour(rarityColour);

			if(slot->getItem()->hasCustomHoverName())
			{
				colour = app.GetHTMLColour(eTextColor_RenamedItemTitle);
			}

			swprintf(formatted, 256, L"<font color=\"#%08x\">%ls</font>",colour,thisString.c_str());				
			thisString = formatted;
		}
		desc.append( thisString );
	}
	strings->clear();
	delete strings;
	return desc;
}
