//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//=============================================================================//

#include <assert.h>
#include <ctype.h>

#include <vgui/MouseCode.h>
#include <vgui/KeyCode.h>
#include <KeyValues.h>
#include <vgui/ISurface.h>
#include <vgui/IVGui.h>
#include <vgui/IInput.h>
#include <vgui/IPanel.h>
#include <vgui/ILocalize.h>

#include <vgui_controls/Controls.h>
#include <vgui_controls/ScrollBar.h>
#include <vgui_controls/ImageList.h>
#include <vgui_controls/ImagePanel.h>
#include <vgui_controls/Label.h>
#include <vgui_controls/TextImage.h>
#include <vgui_controls/ListViewPanel.h>

// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>

using namespace vgui;
	
enum 
{
	WINDOW_BORDER_WIDTH=2 // the width of the window's border
};

namespace vgui
{
class ListViewItem : public Label
{
	DECLARE_CLASS_SIMPLE( ListViewItem, Label );

public:
	ListViewItem(Panel *parent) : Label(parent, NULL, "")
	{
		m_pListViewPanel = (ListViewPanel*) parent;
		m_pData = NULL;
		m_bSelected = false;
		SetPaintBackgroundEnabled(true);
	}

	~ListViewItem()
	{
		if (m_pData)
		{
			m_pData->deleteThis();
			m_pData = NULL;
		}
	}

	void SetData(const KeyValues *data)
	{
		if (m_pData)
		{
			m_pData->deleteThis();
		}
		m_pData = data->MakeCopy();
	}

	virtual void OnMousePressed( MouseCode code)
	{
		m_pListViewPanel->OnItemMousePressed(this, code);
	}

	virtual void OnMouseDoublePressed( MouseCode code)
	{
		// double press should only select the item
		m_pListViewPanel->OnItemMouseDoublePressed(this, code);
	}

	KeyValues *GetData()
	{ 
		return m_pData;
	}

	void SetSelected(bool bSelected)
	{
		if (bSelected == m_bSelected)
			return;

		m_bSelected = bSelected;
		if (bSelected)
		{
			RequestFocus();
		}

		UpdateImage();
		InvalidateLayout();
		Repaint();
	}

	virtual void PerformLayout()
	{
		TextImage *textImage = GetTextImage();
		if (m_bSelected)
		{
			VPANEL focus = input()->GetFocus();
			// if one of the children of the SectionedListPanel has focus, then 'we have focus' if we're selected
			if (HasFocus() || (focus && ipanel()->HasParent(focus, GetVParent())))
			{
				textImage->SetColor(m_ArmedFgColor2);
			}
			else
			{
				textImage->SetColor(m_FgColor2);
			}
		}
		else
		{
			textImage->SetColor(GetFgColor());					
		}
		BaseClass::PerformLayout();
		Repaint();
	}

	virtual void PaintBackground()	
	{
		int wide, tall;
		GetSize(wide, tall);

		if ( m_bSelected )
		{
            VPANEL focus = input()->GetFocus();
            // if one of the children of the SectionedListPanel has focus, then 'we have focus' if we're selected
            if (HasFocus() || (focus && ipanel()->HasParent(focus, GetVParent())))
            {
			    surface()->DrawSetColor(m_ArmedBgColor);
            }
            else
            {
			    surface()->DrawSetColor(m_SelectionBG2Color);
            }
		}
		else
		{
			surface()->DrawSetColor(GetBgColor());
		}
		surface()->DrawFilledRect(0, 0, wide, tall);
	}

	virtual void ApplySchemeSettings(IScheme *pScheme)
	{
		BaseClass::ApplySchemeSettings(pScheme);

		m_ArmedFgColor2 = GetSchemeColor("ListPanel.SelectedTextColor", pScheme);
		m_ArmedBgColor = GetSchemeColor("ListPanel.SelectedBgColor", pScheme);

		m_FgColor1 = GetSchemeColor("ListPanel.TextColor", pScheme);
		m_FgColor2 = GetSchemeColor("ListPanel.SelectedTextColor", pScheme);

		m_BgColor = GetSchemeColor("ListPanel.BgColor", GetBgColor(), pScheme);
		m_BgColor = GetSchemeColor("ListPanel.TextBgColor", m_BgColor, pScheme);
		m_SelectionBG2Color = GetSchemeColor("ListPanel.SelectedOutOfFocusBgColor", pScheme);
		SetBgColor(m_BgColor);
		SetFgColor(m_FgColor1);

		UpdateImage();
	}

	void UpdateImage()
	{
		if ( m_pListViewPanel->m_pImageList )
		{
			int imageIndex = 0;
			if ( m_bSelected )
			{
				imageIndex = m_pData->GetInt("imageSelected", 0);
			}
			if ( imageIndex == 0 )
			{
				imageIndex = m_pData->GetInt("image", 0);
			}
			if ( m_pListViewPanel->m_pImageList->IsValidIndex(imageIndex) )
			{
				SetImageAtIndex(0, m_pListViewPanel->m_pImageList->GetImage(imageIndex), 0);
			}
			else
			{
				// use the default 
				SetImageAtIndex(0, m_pListViewPanel->m_pImageList->GetImage(1), 0);
			}
			SizeToContents();
			InvalidateLayout();
		}
	}

private:

	Color m_FgColor1;
	Color m_FgColor2;
	Color m_BgColor;
	Color m_ArmedFgColor2;
	Color m_ArmedBgColor;
	Color m_SelectionBG2Color;

	//IBorder			  *_keyFocusBorder;		// maybe in the future when I'm the 'active' but not selected item, I'll have a border

	KeyValues 			*m_pData;
	ListViewPanel		*m_pListViewPanel;
	bool				m_bSelected;
};
}

static bool DefaultSortFunc(KeyValues *kv1, KeyValues *kv2)
{
	const char *string1 = kv1->GetString("text");
	const char *string2 = kv2->GetString("text");
	return Q_stricmp(string1, string2) < 0;
}

DECLARE_BUILD_FACTORY( ListViewPanel );

//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
ListViewPanel::ListViewPanel(Panel *parent, const char *panelName) : Panel(parent, panelName)
{
	m_iRowHeight = 20;
	m_bNeedsSort = false;
	m_hFont = NULL;
	m_pImageList = NULL;
	m_bDeleteImageListWhenDone = false;
	m_pSortFunc = DefaultSortFunc;
	m_ShiftStartItemID = -1;

	m_hbar = new ScrollBar(this, "HorizScrollBar", false);
	m_hbar->AddActionSignalTarget(this);
	m_hbar->SetVisible(false);
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
ListViewPanel::~ListViewPanel()
{
	DeleteAllItems();

	delete m_hbar;

	if ( m_bDeleteImageListWhenDone )
	{
		delete m_pImageList;
		m_pImageList = NULL;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int ListViewPanel::AddItem(const KeyValues *data, bool bScrollToItem, bool bSortOnAdd)
{
	ListViewItem *pNewItem = new ListViewItem(this);
	pNewItem->SetData(data);
	if (m_hFont)
	{
		pNewItem->SetFont(m_hFont);
	}
	int itemID = m_DataItems.AddToTail(pNewItem);
	ApplyItemChanges(itemID);
	m_SortedItems.AddToTail(itemID);

	if ( bSortOnAdd )
	{
		m_bNeedsSort = true;
	}

	InvalidateLayout();

	if ( bScrollToItem )
	{
		ScrollToItem(itemID);
	}

	return itemID;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::ScrollToItem(int itemID)
{
	if (!m_hbar->IsVisible())
	{
		return;
	}
	int val = m_hbar->GetValue();

	int wide, tall;
	GetSize( wide, tall );

	int maxWidth = GetItemsMaxWidth();
	int maxColVisible = wide / maxWidth;
	int itemsPerCol = GetItemsPerColumn();

	int itemIndex = m_SortedItems.Find(itemID);
	int desiredCol = itemIndex / itemsPerCol;
	if (desiredCol < val || desiredCol >= (val + maxColVisible) )
	{
		m_hbar->SetValue(desiredCol);
	}

	InvalidateLayout();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int ListViewPanel::GetItemCount()
{
	return m_DataItems.Count();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
KeyValues *ListViewPanel::GetItem(int itemID)
{
	if ( !m_DataItems.IsValidIndex(itemID) )
		return NULL;

	return m_DataItems[itemID]->GetData();
}

//-----------------------------------------------------------------------------
// Purpose: Get ItemID from position in panel - valid from [0, GetItemCount)
//-----------------------------------------------------------------------------
int ListViewPanel::GetItemIDFromPos(int iPos)
{
	if ( m_SortedItems.IsValidIndex(iPos) )
	{
		return m_SortedItems[iPos];
	}
	else
	{
		return m_DataItems.InvalidIndex();
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::ApplyItemChanges(int itemID)
{
	if ( !m_DataItems.IsValidIndex(itemID) )
		return;
		
	KeyValues *kv = m_DataItems[itemID]->GetData();
	ListViewItem *pLabel = m_DataItems[itemID];

	pLabel->SetText(kv->GetString("text"));
	pLabel->SetTextImageIndex(1);
	pLabel->SetImagePreOffset(1, 5);

	TextImage *pTextImage = pLabel->GetTextImage();
	pTextImage->ResizeImageToContent();

	pLabel->UpdateImage();
	pLabel->SizeToContents();
	pLabel->InvalidateLayout();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::RemoveItem(int itemID)
{
	if ( !m_DataItems.IsValidIndex(itemID) )
		return;

	m_DataItems[itemID]->MarkForDeletion();

	// mark the keyValues for deletion
	m_DataItems.Remove(itemID);
	m_SortedItems.FindAndRemove(itemID);
	m_SelectedItems.FindAndRemove(itemID);

	InvalidateLayout();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::DeleteAllItems()
{
	FOR_EACH_LL( m_DataItems, index )
	{
		m_DataItems[index]->MarkForDeletion();
	}
	m_DataItems.RemoveAll();
	m_SortedItems.RemoveAll();
	m_SelectedItems.RemoveAll();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int ListViewPanel::InvalidItemID()
{
	return m_DataItems.InvalidIndex();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool ListViewPanel::IsValidItemID(int itemID)
{
	return m_DataItems.IsValidIndex(itemID);
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::SetSortFunc(ListViewSortFunc_t func)
{
	if ( func )
	{
		m_pSortFunc = func;
		SortList();
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::SortList()
{
	m_SortedItems.RemoveAll();

	// find all the items in this section
	for( int i = m_DataItems.Head(); i != m_DataItems.InvalidIndex(); i = m_DataItems.Next( i ) )
	{
		// insert the items sorted
		if (m_pSortFunc)
		{
			int insertionPoint;
			for (insertionPoint = 0; insertionPoint < m_SortedItems.Count(); insertionPoint++)
			{
				if ( m_pSortFunc(m_DataItems[i]->GetData(), m_DataItems[m_SortedItems[insertionPoint]]->GetData() ) )
					break;
			}
	
			if (insertionPoint == m_SortedItems.Count())
			{
				m_SortedItems.AddToTail(i);
			}
			else
			{
				m_SortedItems.InsertBefore(insertionPoint, i);
			}
		}
		else
		{
			// just add to the end
			m_SortedItems.AddToTail(i);
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::SetImageList(ImageList *imageList, bool deleteImageListWhenDone)
{
	// get rid of existing list image if there's one and we're supposed to get rid of it
	if ( m_pImageList && m_bDeleteImageListWhenDone )
	{
		delete m_pImageList;
		m_pImageList = NULL;
	}

	m_bDeleteImageListWhenDone = deleteImageListWhenDone;
	m_pImageList = imageList;

	FOR_EACH_LL( m_DataItems, i )
	{
		m_DataItems[i]->UpdateImage();
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::SetFont(HFont font)
{
	Assert( font );
	if ( !font )
		return;

	m_hFont = font;
	m_iRowHeight = surface()->GetFontTall(font) + 1;
	
	FOR_EACH_LL( m_DataItems, i )
	{
		m_DataItems[i]->SetFont(m_hFont);
		TextImage *pTextImage = m_DataItems[i]->GetTextImage();
		pTextImage->ResizeImageToContent();
		m_DataItems[i]->SizeToContents();
	}
}
	
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int ListViewPanel::GetSelectedItemsCount()
{
	return m_SelectedItems.Count();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int ListViewPanel::GetSelectedItem(int selectionIndex)
{
	if ( m_SelectedItems.IsValidIndex(selectionIndex) )
		return m_SelectedItems[selectionIndex];

	return -1;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::ClearSelectedItems()
{
	int i;
	for (i = 0 ; i < m_SelectedItems.Count(); i++)
	{
		if ( m_DataItems.IsValidIndex(m_SelectedItems[i]) )
		{
			m_DataItems[m_SelectedItems[i]]->SetSelected(false);
		}
	}
	m_SelectedItems.RemoveAll();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::AddSelectedItem(int itemID)
{
	if ( m_SelectedItems.Find(itemID) == -1 )
	{
		m_SelectedItems.AddToTail(itemID);
		m_DataItems[itemID]->SetSelected(true);
		m_LastSelectedItemID = itemID;
		m_ShiftStartItemID = itemID;
		PostActionSignal(new KeyValues("ListViewItemSelected"));
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::SetSingleSelectedItem(int itemID)
{
	ClearSelectedItems();
	AddSelectedItem(itemID);
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::OnMouseWheeled(int delta)
{
	int val = m_hbar->GetValue();
	val -= delta;
	m_hbar->SetValue(val);
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::OnSizeChanged(int wide, int tall)
{
	BaseClass::OnSizeChanged(wide, tall);
	InvalidateLayout();
	Repaint();
}
	
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int ListViewPanel::GetItemsMaxWidth()
{
	int maxWidth = 0;
	FOR_EACH_LL( m_DataItems, i )
	{
		int labelWide, labelTall;
		m_DataItems[i]->GetSize(labelWide, labelTall);
		if (labelWide > maxWidth)
		{
			maxWidth = labelWide + 25;
		}
	}
	return maxWidth;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::PerformLayout()
{
	if (m_bNeedsSort)
	{
		SortList();
	}

	if ( m_DataItems.Count() == 0 )
		return;

	int wide, tall;
	GetSize(wide, tall);

	int maxWidth = GetItemsMaxWidth();
	if (maxWidth < 24)
	{
		maxWidth = 24;
	}
	int maxColVisible = wide / maxWidth;

	m_hbar->SetVisible(false);
	int itemsPerCol = GetItemsPerColumn();
	if (itemsPerCol < 1)
	{
		itemsPerCol = 1;
	}
	int cols = ( GetItemCount() + (itemsPerCol - 1) ) / itemsPerCol;

	int startItem = 0;
	if ( cols > maxColVisible)
	{
		m_hbar->SetVisible(true);

		// recalulate # per column now that we've made the hbar visible
		itemsPerCol = GetItemsPerColumn();
		cols = ( GetItemCount() + (itemsPerCol - 1) ) / (itemsPerCol > 0 ? itemsPerCol : 1 );

		m_hbar->SetEnabled(false);
		m_hbar->SetRangeWindow( maxColVisible );
		m_hbar->SetRange( 0, cols);	
		m_hbar->SetButtonPressedScrollValue( 1 );
	
		m_hbar->SetPos(0, tall - (m_hbar->GetTall()+WINDOW_BORDER_WIDTH));
		m_hbar->SetSize(wide - (WINDOW_BORDER_WIDTH*2), m_hbar->GetTall());
		m_hbar->InvalidateLayout();

		int val = m_hbar->GetValue();
		startItem += val*itemsPerCol;
	}
	else
	{
		m_hbar->SetVisible(false);
	}
	int lastItemVisible = startItem + (( maxColVisible + 1 )* itemsPerCol) - 1;

	int itemsThisCol = 0;
	int x = 0;
	int y = 0;
	int i;
	for ( i = 0 ; i < m_SortedItems.Count() ; i++ )
	{
		if ( i >= startItem && i <= lastItemVisible )
		{
			m_DataItems[ m_SortedItems[i] ]->SetVisible(true);
			m_DataItems[ m_SortedItems[i] ]->SetPos(x, y);
			itemsThisCol++;
			if ( itemsThisCol == itemsPerCol )
			{
				y = 0;
				x += maxWidth;
				itemsThisCol = 0;
			}
			else
			{
				y += m_iRowHeight;
			}
		}
		else
		{
			m_DataItems[ m_SortedItems[i] ]->SetVisible(false);
		}
	}
}
 
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::Paint()
{
	BaseClass::Paint();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::ApplySchemeSettings(IScheme *pScheme)
{
	BaseClass::ApplySchemeSettings(pScheme);

	SetBgColor(GetSchemeColor("ListPanel.BgColor", pScheme));
	SetBorder(pScheme->GetBorder("ButtonDepressedBorder"));

	m_LabelFgColor = GetSchemeColor("ListPanel.TextColor", pScheme);
	m_SelectionFgColor = GetSchemeColor("ListPanel.SelectedTextColor", m_LabelFgColor, pScheme);
		
	m_hFont = pScheme->GetFont("Default", IsProportional());
	SetFont(m_hFont);
}
	
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::OnMousePressed( MouseCode code)
{
	if (code == MOUSE_LEFT || code == MOUSE_RIGHT)
	{
		ClearSelectedItems();		
		RequestFocus();
	}
	// check for context menu open
	if (code == MOUSE_RIGHT)
	{
		// post it, but with the invalid row
		PostActionSignal(new KeyValues("OpenContextMenu", "itemID", -1));
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::OnShiftSelect(int itemID)
{
	// if we dont' have a valid selected ItemID - then we just choose the first item
	if ( !m_DataItems.IsValidIndex(m_ShiftStartItemID) )
	{
		m_ShiftStartItemID = m_DataItems.Head();
	}

	// find out if the just pressed item is "earlier" or is the 'last selected item' 
	int lowerPos = -1, upperPos = -1;
	int i;
	for ( i = 0 ; i < m_SortedItems.Count() ; i++ )
	{
		if ( m_SortedItems[i] == itemID )
		{
			lowerPos = i;
			upperPos = m_SortedItems.Find(m_ShiftStartItemID);
			break;
		}
		else if ( m_SortedItems[i] == m_ShiftStartItemID )
		{
			lowerPos = m_SortedItems.Find(m_ShiftStartItemID);
			upperPos = i;
			break;
		}
	}
	assert(lowerPos <= upperPos);
	if ( !input()->IsKeyDown(KEY_LCONTROL) && !input()->IsKeyDown(KEY_RCONTROL) )
	{
		ClearSelectedItems();		
	}

	for ( i = lowerPos ; i <= upperPos ; i ++)
	{
		// do not use AddSelectedItem because we don't want to switch the shiftStartItemID
		m_DataItems[ m_SortedItems[i] ]->SetSelected(true);
		m_SelectedItems.AddToTail(m_SortedItems[i]);
		m_LastSelectedItemID = itemID;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::OnItemMousePressed(ListViewItem* pItem, MouseCode code)
{
	int itemID = m_DataItems.Find(pItem);
	if (!m_DataItems.IsValidIndex(itemID))
		return;
	
	// check for context menu open
	if (code == MOUSE_RIGHT)
	{
		// if this is a new item - unselect everything else
		if ( m_SelectedItems.Find(itemID) == -1)
		{
			ClearSelectedItems();		
			AddSelectedItem(itemID);
		}

		PostActionSignal(new KeyValues("OpenContextMenu", "itemID", itemID));
	}
	else
	{
		if ( input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT) ) 
		{
			OnShiftSelect(itemID);
		}
		else if ( input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL) )
		{
			if ( m_SelectedItems.Find(itemID) != -1)
			{
				m_SelectedItems.FindAndRemove(itemID);
				pItem->SetSelected(false);
	
				// manually select these since we 'last' clicked on these items
				m_ShiftStartItemID = itemID;
				m_LastSelectedItemID = itemID;
				m_DataItems[itemID]->RequestFocus();
			}
			else
			{
				AddSelectedItem(itemID);
			}
		}
		else
		{
			ClearSelectedItems();		
			AddSelectedItem(itemID);
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::OnMouseDoublePressed( MouseCode code)
{
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::OnItemMouseDoublePressed(ListViewItem* pItem, MouseCode code)
{
	if (code == MOUSE_LEFT)
	{
		OnKeyCodeTyped(KEY_ENTER);
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::FinishKeyPress(int itemID)
{
	if ( input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT) ) 
	{
		OnShiftSelect(itemID);
	}
	else if ( input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL) )
	{
		m_DataItems[itemID]->RequestFocus();
		m_LastSelectedItemID = itemID;
	}
	else
	{
		SetSingleSelectedItem(itemID);
	}
	ScrollToItem(itemID);
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::OnKeyCodeTyped( KeyCode code )
{
	if ( m_DataItems.Count() == 0 )
		return;

	switch (code)
	{
		case KEY_HOME:
		{
			if (m_SortedItems.Count() > 0)
			{
				int itemID = m_SortedItems[0];
				FinishKeyPress(itemID);
			}
			break;
		}
		case KEY_END:
		{
			if (m_DataItems.Count() > 0)
			{
				int itemID = m_SortedItems[ m_SortedItems.Count() - 1 ];
				FinishKeyPress(itemID);
			}
			break;
		}

		case KEY_UP:
		{
			int itemPos = m_SortedItems.Find( m_LastSelectedItemID );
			itemPos--;
			if (itemPos < 0)
				itemPos = 0;

			FinishKeyPress(m_SortedItems[itemPos]);
			break;
		}
		
		case KEY_DOWN:
		{
			int itemPos = m_SortedItems.Find( m_LastSelectedItemID );
			itemPos++;
			if (itemPos >= m_DataItems.Count())
				itemPos = m_DataItems.Count() - 1;

			FinishKeyPress(m_SortedItems[itemPos]);
			break;
		}

		case KEY_LEFT:
		{
			int itemPos = m_SortedItems.Find( m_LastSelectedItemID );
			itemPos -= GetItemsPerColumn();
			if (itemPos < 0)
			{
				itemPos = 0;
			}
			FinishKeyPress(m_SortedItems[itemPos]);
			break;
		}

		case KEY_RIGHT:
		{
			int itemPos = m_SortedItems.Find( m_LastSelectedItemID );
			itemPos += GetItemsPerColumn();
			if (itemPos >= m_SortedItems.Count())
			{
				itemPos = m_SortedItems.Count() - 1;
			}
			FinishKeyPress(m_SortedItems[itemPos]);
			break;
		}

		case KEY_PAGEUP:
		{
			int wide, tall;
			GetSize(wide, tall);

			int maxWidth = GetItemsMaxWidth();
			if (maxWidth == 0)
			{
				maxWidth = wide;
			}
			int maxColVisible = wide / maxWidth;
			int delta = maxColVisible * GetItemsPerColumn();

			int itemPos = m_SortedItems.Find( m_LastSelectedItemID );
			itemPos -= delta;
			if (itemPos < 0)
			{
				itemPos = 0;
			}

			FinishKeyPress(m_SortedItems[itemPos]);
			break;
		}
		case KEY_PAGEDOWN:
		{
			int wide, tall;
			GetSize(wide, tall);

			int maxWidth = GetItemsMaxWidth();
			if (maxWidth == 0)
			{
				maxWidth = wide;
			}
			int maxColVisible = wide / maxWidth;
			int delta = maxColVisible * GetItemsPerColumn();

			int itemPos = m_SortedItems.Find( m_LastSelectedItemID );
			itemPos += delta;
			if (itemPos >= m_SortedItems.Count())
			{
				itemPos = m_SortedItems.Count() - 1;
			}

			FinishKeyPress(m_SortedItems[itemPos]);
			break;
		}
		default:
		{
			BaseClass::OnKeyCodeTyped(code);
			break;
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::OnKeyTyped(wchar_t unichar)
{
	if (!iswcntrl(unichar))
	{
		wchar_t uniString[2];
		uniString[0] = unichar;
		uniString[1] = 0;

		char buf[2];
		g_pVGuiLocalize->ConvertUnicodeToANSI(uniString, buf, sizeof(buf));

		int i; 
		int itemPos = m_SortedItems.Find(m_LastSelectedItemID);
		if ( m_SortedItems.IsValidIndex(itemPos))
		{
			itemPos++;
			// start from the item AFTER our last selected Item and go to end
			for ( i = itemPos ; i != m_SortedItems.Count(); i++)
			{
				KeyValues *kv = m_DataItems[ m_SortedItems[i] ]->GetData();
				const char *pszText = kv->GetString("text");
				if (!strnicmp(pszText, buf, 1))
				{
					// select the next of this letter
					SetSingleSelectedItem(m_SortedItems[i]);
					ScrollToItem(m_SortedItems[i]);
					return;
				}
			}
			// if the after this item we couldn't fine an item with  the same letter, fall through and just start from the beginning of list to the last selected item
		}

		for ( i = 0 ; i < m_SortedItems.Count() ; i++ )
		{
			// we've gone all the way around - break - if we had a valid index, this is one more that last selectedItem, if not it's an illegal index
			if ( i == itemPos)
				break;

			KeyValues *kv = m_DataItems[ m_SortedItems[i] ]->GetData();
			const char *pszText = kv->GetString("text");
			if (!strnicmp(pszText, buf, 1))
			{
				SetSingleSelectedItem(m_SortedItems[i]);
				ScrollToItem(m_SortedItems[i]);
				return;
			}
		}
	}
	else
		BaseClass::OnKeyTyped(unichar);
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ListViewPanel::OnSliderMoved()
{
	InvalidateLayout();
	Repaint();
}
 
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int ListViewPanel::GetItemsPerColumn()
{
	int wide, tall;
	GetSize(wide, tall);

	if ( m_hbar->IsVisible() )
	{
		tall -= m_hbar->GetTall();
	}

	return tall / m_iRowHeight;	// should round down
}