//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============

//

// Purpose: 

//

// $NoKeywords: $

//=============================================================================



#include <assert.h>

#include "vgui_grid.h"





using namespace vgui;





#define AssertCheck(expr, msg) \

	if(!(expr))\

	{\

		assert(!msg);\

		return 0;\

	}







// ------------------------------------------------------------------------------ //

// CGrid::CGridEntry.

// ------------------------------------------------------------------------------ //



CGrid::CGridEntry::CGridEntry()

{

	m_pPanel = NULL;

	m_bUnderline = false;

}



CGrid::CGridEntry::~CGridEntry()

{

}





// ------------------------------------------------------------------------------ //

// CGrid.

// ------------------------------------------------------------------------------ //



CGrid::CGrid()

{

	Clear();

}





CGrid::~CGrid()

{

	Term();

}





bool CGrid::SetDimensions(int xCols, int yRows)

{

	Term();



	m_GridEntries = new CGridEntry[xCols * yRows];

	m_Widths = new int[xCols*2 + yRows*2];

	m_Heights = m_Widths + xCols;

	m_ColOffsets = m_Heights + yRows;

	m_RowOffsets = m_ColOffsets + xCols;



	if(!m_GridEntries || !m_Widths)

	{

		Term();

		return false;

	}



	memset(m_Widths, 0, sizeof(int) * (xCols*2 + yRows*2));



	m_xCols = xCols;

	m_yRows = yRows;

	return true;

}





void CGrid::Term()

{

	delete [] m_GridEntries;

	delete [] m_Widths;

	Clear();

}





Panel* CGrid::GetEntry(int x, int y)

{

	return GridEntry(x, y)->m_pPanel;

}





bool CGrid::SetEntry(int x, int y, Panel *pPanel)

{

	CGridEntry *pEntry = GridEntry(x, y);

	if(!pEntry)

		return false;



	if(pEntry->m_pPanel)

		pEntry->m_pPanel->setParent(NULL);



	pEntry->m_pPanel = pPanel;

	if(pPanel)

		pPanel->setParent(this);



	m_bDirty = true;

	return true;

}





int CGrid::GetXSpacing()

{

	return m_xSpacing;

}





int CGrid::GetYSpacing()

{

	return m_ySpacing;

}





void CGrid::SetSpacing(int xSpacing, int ySpacing)

{

	if(xSpacing != m_xSpacing)

	{

		m_xSpacing = xSpacing;

		CalcColOffsets(0);

		m_bDirty = true;

	}



	if(ySpacing != m_ySpacing)

	{

		m_ySpacing = ySpacing;

		CalcRowOffsets(0);

		m_bDirty = true;

	}

}





bool CGrid::SetColumnWidth(int iColumn, int width)

{

	AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::SetColumnWidth : invalid location specified");

	m_Widths[iColumn] = width;

	CalcColOffsets(iColumn+1);

	m_bDirty = true;

	return true;

}





bool CGrid::SetRowHeight(int iRow, int height)

{

	AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::SetColumnWidth : invalid location specified");

	m_Heights[iRow] = height;

	CalcRowOffsets(iRow+1);

	m_bDirty = true;

	return true;

}





int CGrid::GetColumnWidth(int iColumn)

{

	AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::GetColumnWidth: invalid location specified");

	return m_Widths[iColumn];

}





int CGrid::GetRowHeight(int iRow)

{

	AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::GetRowHeight: invalid location specified");

	return m_Heights[iRow];

}





int CGrid::CalcFitColumnWidth(int iColumn)

{

	AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::CalcFitColumnWidth: invalid location specified");



	int maxSize = 0;

	for(int i=0; i < m_yRows; i++)

	{

		Panel *pPanel = GridEntry(iColumn, i)->m_pPanel;

		if(!pPanel)

			continue;



		int w, h;

		pPanel->getSize(w,h);

		if(w > maxSize)

			maxSize = w;

	}



	return maxSize;

}





int CGrid::CalcFitRowHeight(int iRow)

{

	AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::CalcFitRowHeight: invalid location specified");



	int maxSize = 0;

	for(int i=0; i < m_xCols; i++)

	{

		Panel *pPanel = GridEntry(i, iRow)->m_pPanel;

		if(!pPanel)

			continue;



		int w, h;

		pPanel->getSize(w,h);

		if(h > maxSize)

			maxSize = h;

	}



	return maxSize;

}





void CGrid::AutoSetRowHeights()

{

	for(int i=0; i < m_yRows; i++)

		SetRowHeight(i, CalcFitRowHeight(i));

}





bool CGrid::GetEntryBox(

	int col, int row, int &x, int &y, int &w, int &h)

{

	AssertCheck(col >= 0 && col < m_xCols && row >= 0 && row < m_yRows, "CGrid::GetEntryBox: invalid location specified");



	x = m_ColOffsets[col];

	w = m_Widths[col];



	y = m_RowOffsets[row];

	h = m_Heights[row];

	return true;	

}





bool CGrid::CopyColumnWidths(CGrid *pOther)

{

	if(!pOther || pOther->m_xCols != m_xCols)

		return false;



	for(int i=0; i < m_xCols; i++)

		m_Widths[i] = pOther->m_Widths[i];



	CalcColOffsets(0);

	m_bDirty = true;

	return true;

}





void CGrid::RepositionContents()

{

	for(int x=0; x < m_xCols; x++)

	{

		for(int y=0; y < m_yRows; y++)

		{

			Panel *pPanel = GridEntry(x,y)->m_pPanel;

			if(!pPanel)

				continue;



			pPanel->setBounds(

				m_ColOffsets[x], 

				m_RowOffsets[y],

				m_Widths[x], 

				m_Heights[y]);

		}

	}



	m_bDirty = false;

}





int CGrid::CalcDrawHeight()

{

	if(m_yRows > 0)

	{

		return m_RowOffsets[m_yRows-1] + m_Heights[m_yRows - 1] + m_ySpacing;

	}

	else

	{

		return 0;

	}

}





void CGrid::paint()

{

	if(m_bDirty)

		RepositionContents();



	Panel::paint();



	// walk the grid looking for underlined rows

	int x = 0, y = 0;

	for (int row = 0; row < m_yRows; row++)

	{

		CGridEntry *cell = GridEntry(0, row);



		y += cell->m_pPanel->getTall() + m_ySpacing;

		if (cell->m_bUnderline)

		{

			drawSetColor(cell->m_UnderlineColor[0], cell->m_UnderlineColor[1], cell->m_UnderlineColor[2], cell->m_UnderlineColor[3]);

			drawFilledRect(0, y - (cell->m_iUnderlineOffset + 1), getWide(), y - cell->m_iUnderlineOffset);

		}

	}

}



void CGrid::paintBackground()

{

	Panel::paintBackground();

}



//-----------------------------------------------------------------------------

// Purpose: sets underline color for a particular row

//-----------------------------------------------------------------------------

void CGrid::SetRowUnderline(int row, bool enabled, int offset, int r, int g, int b, int a)

{

	CGridEntry *cell = GridEntry(0, row);

	cell->m_bUnderline = enabled;

	if (enabled)

	{

		cell->m_iUnderlineOffset = offset;

		cell->m_UnderlineColor[0] = r;

		cell->m_UnderlineColor[1] = g;

		cell->m_UnderlineColor[2] = b;

		cell->m_UnderlineColor[3] = a;

	}

}



void CGrid::Clear()

{

	m_xCols = m_yRows = 0;

	m_Widths = NULL;

	m_GridEntries = NULL;

	m_xSpacing = m_ySpacing = 0;

	m_bDirty = false;

}





CGrid::CGridEntry* CGrid::GridEntry(int x, int y)

{

	AssertCheck(x >= 0 && x < m_xCols && y >= 0 && y < m_yRows, "CGrid::GridEntry: invalid location specified");

	return &m_GridEntries[y*m_xCols + x];

}





void CGrid::CalcColOffsets(int iStart)

{

	int cur = m_xSpacing;

	if(iStart != 0)

		cur += m_ColOffsets[iStart-1] + m_Widths[iStart-1];



	for(int i=iStart; i < m_xCols; i++)

	{

		m_ColOffsets[i] = cur;

		cur += m_Widths[i] + m_xSpacing;

	}

}





void CGrid::CalcRowOffsets(int iStart)

{

	int cur = m_ySpacing;

	if(iStart != 0)

		cur += m_RowOffsets[iStart-1];



	for(int i=iStart; i < m_yRows; i++)

	{

		m_RowOffsets[i] = cur;

		cur += m_Heights[i] + m_ySpacing;

	}

}



bool CGrid::getCellAtPoint(int worldX, int worldY, int &row, int &col)

{

	row = -1; col = -1;

	for(int x=0; x < m_xCols; x++)

	{

		for(int y=0; y < m_yRows; y++)

		{

			Panel *pPanel = GridEntry(x,y)->m_pPanel;

			if (!pPanel)

				continue;



			if (pPanel->isWithin(worldX, worldY))

			{

				col = x;

				row = y;

				return true;

			}

		}

	}

		

	return false;

}





