Click here to Skip to main content
15,884,388 members
Articles / Desktop Programming / ATL

CM_ConfigBuilder 1.2g: Visual Studio 6/Visual Studio 2005/Visual Studio 2008 Code Generator for Application Settings Graphic Management

Rate me:
Please Sign up or sign in to vote.
4.94/5 (126 votes)
12 Feb 2008CPOL17 min read 696.3K   9.8K   262  
CM_ConfigBuilder generates and compiles the required files to manage your application's settings/preferences and to store/retrieve them in XML format.
// AsTable.cpp : implementation file
//

#include "stdafx.h"
#include "AsTable.h"
#include "MemDC.h"
#include "AsTableRow.h"
#include "AsBaseCell.h"
#include "DrawUtils.h"
#include <assert.h>

/*
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
*/

#define BORDER 1
/////////////////////////////////////////////////////////////////////////////
// CAsTable

CAsTable::CAsTable():
	bkColor_(::GetSysColor(COLOR_BTNFACE)),
	borderColor_(::GetSysColor(COLOR_3DSHADOW)),
	defaultRowHeight_(22),
	horizontalOffset_(0),
	fixedColumnsNumber_(0),
	fixedRowsNumber_(0),
	firstNonFixedRowIndex_(0),
	firstNonFixedColumnIndex_(0),
	rowsNumber_(0),
	columnsNumber_(0),
	vScrollMinPos_(0),
	vScrollMaxPos_(0),
	vScrollPageSize_(0),
	hScrollMinPos_(0),
	hScrollMaxPos_(0),
	hScrollPageSize_(0),
	selSplitterIndex_(-1),
	splitterRowIndex_(-1),
	draggingSplitter_(false)
{
	WNDCLASS wndcls;
    HINSTANCE hInst = AfxGetInstanceHandle();
    //HINSTANCE hInst = AfxGetResourceHandle();

    if (!(::GetClassInfo(hInst, _T("AsTable"), &wndcls)))
    {
        // otherwise we need to register a new class
        wndcls.style            = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
        wndcls.lpfnWndProc      = ::DefWindowProc;
        wndcls.cbClsExtra       = wndcls.cbWndExtra = 0;
        wndcls.hInstance        = hInst;
        wndcls.hIcon            = NULL;
        wndcls.hCursor          = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
        wndcls.hbrBackground    = (HBRUSH) (COLOR_3DFACE + 1);
        wndcls.lpszMenuName     = NULL;
        wndcls.lpszClassName    = _T("AsTable");

        if (!AfxRegisterClass(&wndcls))
        {
            AfxThrowResourceException();
            return;
        }
    }
}

CAsTable::~CAsTable()
{
	Clear();
}

BEGIN_MESSAGE_MAP(CAsTable, CWnd)
	//{{AFX_MSG_MAP(CAsTable)
	ON_WM_ERASEBKGND()
	ON_WM_SIZE()
	ON_WM_PAINT()
	ON_WM_VSCROLL()
	ON_WM_HSCROLL()
	ON_WM_SETCURSOR()
	ON_WM_MOUSEWHEEL()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CAsTable message handlers

BOOL CAsTable::Create(const CRect& rc, CWnd* parentWnd, DWORD style, UINT nID)
{
	BOOL ret;

	style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN | /*WS_VSCROLL | WS_HSCROLL |*/ WS_CHILD | WS_VISIBLE;
	
	ret = CWnd::Create(_T("AsTable"), _T("Algostar Table"), style, rc, parentWnd, nID, NULL);


	return ret;
}


BOOL CAsTable::OnEraseBkgnd(CDC* pDC) 
{
	return TRUE;
}

void CAsTable::OnSize(UINT nType, int cx, int cy) 
{
	CWnd::OnSize(nType, cx, cy);
	
	UpdateWindowSize();

}

void CAsTable::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	CMemDC memDC(&dc);
	
	DrawBackground(&memDC);
	DrawBorders(&memDC);
	DrawRows(&memDC);
}

void CAsTable::DrawBackground(CDC* pDC)
{
	CBrush b(bkColor_);
	CRect rc;

	GetClientRect(rc);
	pDC->FillRect(rc, &b);
}

void CAsTable::DrawBorders(CDC* pDC)
{
	// main border
	//
	CRect rc;
	CRect tmp;
	GetClientRect(rc);	
	int i;

	rc.DeflateRect(0, 0, 1, 1);
	DrawUtils::DrawRect(pDC, rc, borderColor_);

	for (i = 0; i < fixedRowsNumber_; i++) {
		tmp = rows_[i]->GetDrawArea();
		tmp.InflateRect(1, 1, 0, 0);
		
		DrawUtils::DrawRect(pDC, tmp, borderColor_);
	}

	for (i = firstNonFixedRowIndex_; i < rows_.size(); i++) {
		tmp = rows_[i]->GetDrawArea();
		tmp.InflateRect(1, 1, 0, 0);
		if (!rc.PtInRect(tmp.TopLeft()))
			break;
		DrawUtils::DrawRect(pDC, tmp, borderColor_);
	}
}

void CAsTable::DrawRows(CDC* pDC)
{
	int i;
	CRect rc;
	CAsTableRow* row;
	int lastBottom;
	CRect drawArea;
	GetClientRect(rc);

	for (i = 0; i < fixedRowsNumber_; i++) {
		row = rows_[i];
		if (row)
			row->Draw(pDC);
	}
	lastBottom = 0;
	for (i = firstNonFixedRowIndex_; i < rows_.size(); i++) {
		row = rows_[i];
		if (row) {
			drawArea = row->GetDrawArea();
			if (!rc.PtInRect(drawArea.TopLeft()) || drawArea.top < lastBottom)
				break;
			//TRACE1("drawing row %s\n", row->GetCell(0)->GetText().c_str());
			row->Draw(pDC);
		}
		lastBottom = drawArea.bottom + BORDER;
	}
}

BOOL CAsTable::PreTranslateMessage(MSG* pMsg) 
{
	CPoint pt;
	CRect rc;
	bool ret;
	bool needRedraw = false;
	bool processed = false;

	pt = pMsg->pt;
	ScreenToClient(&pt);
	GetClientRect(rc);

	// first of all check if we are dragging the splitter
	//
	switch (pMsg->message) {
		case WM_LBUTTONDOWN:
			selSplitterIndex_ = HitSplitter(pt);
			if (selSplitterIndex_ != -1) {
				draggingSplitter_ = true;
				return TRUE;
			}
			break;

		case WM_MOUSEMOVE:
			if (draggingSplitter_ && (pMsg->wParam & MK_LBUTTON)) {
				CRect rc;
				int minPos;
				//int maxPos;
				CPoint point(pt);
				GetClientRect(rc);
				CAsBaseCell* cell;
				int cellWidth;
				
				cell = rows_[splitterRowIndex_]->GetCell(selSplitterIndex_);
				cellWidth = cell->GetDrawArea().Width();
				if (selSplitterIndex_ > 0)
					minPos = cell->GetDrawArea().left + 5;
				else
					minPos = 5;
				
				point.x = max(point.x, minPos);

				cellWidth = point.x - cell->GetDrawArea().left;
				SetColumnWidth(selSplitterIndex_, cellWidth);
				UpdateDrawArea();
				TRACE3("splitterIndex = %d, width=%d, x=%d\n", selSplitterIndex_, cellWidth, point.x);
				
				RedrawWindow();
			
				return TRUE;
			}
			
		case WM_LBUTTONUP:
			if (draggingSplitter_) {
				draggingSplitter_ = false;
				selSplitterIndex_ = -1;
				splitterRowIndex_ = - 1;
				return TRUE;
			}
			break;
	}
	
	
	
	CAsTableRow* row;

	for (int i = 0; i < rows_.size(); i++) {
		row = rows_[i];
		processed |= row->ProcessMessage(pMsg->message, pMsg->lParam, pMsg->wParam, pt, rc, needRedraw);
	}

	if (processed)
		return TRUE;

	if (pMsg->message == WM_KEYDOWN && !processed) { 
		switch (pMsg->wParam) {
			case VK_ESCAPE:
				KillCellFocus(false);
				RedrawWindow();
				return TRUE;

			case VK_RETURN:
				KillCellFocus(true);
				MoveSelection(0, 1, true);
				return TRUE;

			case VK_UP:
				MoveSelection(0, -1, true);
				return TRUE;
				break;

			case VK_DOWN:
				MoveSelection(0, 1, true);
				return TRUE;
				break;

			case VK_LEFT:
				ret = MoveSelection(-1, 0, true);
				if (ret)
					return TRUE;
				
				needRedraw = true;
				break;

			case VK_RIGHT:
				ret = MoveSelection(1, 0, true);
				if (ret)
					return TRUE;
				
				needRedraw = true;
				break;

			case VK_F2:
				SetCellFocus(false);
				needRedraw = true;
				break;

		}
	}

	if (needRedraw)
		RedrawWindow();

	return CWnd::PreTranslateMessage(pMsg);
}

void CAsTable::UpdateWindowSize(bool redraw)
{
	UpdateDrawArea();
		
	UpdateFirstNonFixedRowIndex();
	UpdateFirstNonFixedColumnIndex();

	// update vertical scrollbar
	// 
	SCROLLINFO si;
	
	vScrollMinPos_ = 0;
	vScrollMaxPos_ = rows_.size() -  fixedRowsNumber_ - 1;
	vScrollPageSize_ = GetNonFixedRowsPerPage();

	// Setup scroll info
	//
	ZeroMemory(&si, sizeof(SCROLLINFO));
	si.cbSize = sizeof(SCROLLINFO);
	si.fMask = SIF_RANGE | SIF_PAGE;
	si.nMin = vScrollMinPos_;
	si.nMax = vScrollMaxPos_;
	si.nPage = vScrollPageSize_;

	// Set scroll info
	if ((int)si.nPage > si.nMax)
		firstNonFixedRowIndex_ = fixedRowsNumber_;

	SetScrollInfo(SB_VERT, &si, TRUE);
	
	// update horizontal scrollbar
	//
	hScrollMinPos_ = 0;
	hScrollMaxPos_ = columnsNumber_ - fixedColumnsNumber_ - 1;
	hScrollPageSize_ = GetNonFixedColumnsPerPage();

	// Setup scroll info
	ZeroMemory(&si, sizeof(SCROLLINFO));
	si.cbSize = sizeof(SCROLLINFO);
	si.fMask = SIF_RANGE | SIF_PAGE;
	si.nMin = hScrollMinPos_;
	si.nMax = hScrollMaxPos_;
	si.nPage = hScrollPageSize_;

	// Set scroll info
	//
	if ((int)si.nPage > si.nMax)
		firstNonFixedColumnIndex_ = fixedColumnsNumber_;
	
	SetScrollInfo(SB_HORZ, &si, TRUE);
	
	if (redraw) {
		RedrawWindow();
		// -- Redraw
		//Invalidate();

		// -- Update window
		//UpdateWindow();
	}
}

void CAsTable::Clear()
{
	for (int i = 0; i < rows_.size(); i++)
		delete rows_[i];

	rows_.clear();
}

CAsTableRow* CAsTable::AppendRow(int numColumns, bool redraw)
{
	return InsertRow(rows_.size(), numColumns, redraw);
}

CAsTableRow* CAsTable::InsertRow(int index, int numColumns, bool redraw)
{
	CAsTableRow* newRow;

	newRow = new CAsTableRow;
	newRow->SetNumColumns(numColumns);
	newRow->SetColumnWidthList(colWidth_);
	newRow->SetParentWnd(this);
	newRow->SetFixedColumnsNumber(fixedColumnsNumber_);
	if (index < 0)
		index = 0;
	else if (index >= rows_.size())
		index = rows_.size();

	rows_.insert(rows_.begin() + index, newRow);

	UpdateWindowSize(redraw);

	return newRow;
}

void CAsTable::DeleteRow(int index, bool redraw)
{	
	if(index < 0 || index >= rows_.size())
		return;

	delete rows_[index];

	rows_.erase(rows_.begin() + index);

	if (redraw)
		RedrawWindow();
}

CAsTableRow* CAsTable::GetRow(int index)
{
	if(index < 0 || index >= rows_.size())
		return NULL;

	return rows_[index];
}

long CAsTable::GetRowCount() const
{
	return rows_.size();
}

void CAsTable::DeleteAll()
{
	Clear();

	RedrawWindow();
}

void CAsTable::UpdateDrawArea()
{
	CRect rc;
	CRect drawArea;
	CRect tmp;
	CAsTableRow* row;
	int totalHeight;
	int i;
	int rowHeight;

	GetClientRect(rc);

	//rc.InflateRect(horizontalOffset_, verticalOffset_, 0, 0);
	rc.DeflateRect(BORDER, BORDER, BORDER, BORDER);	// remove borders 
	drawArea = rc;
	
	totalHeight = 0;
	i = 0;

	// calculate draw areas for fixed rows
	//
	for (i = 0; (i < fixedRowsNumber_) && (i < rows_.size()); i++) {
		row = rows_[i];	
		drawArea.bottom = drawArea.top + row->GetRowHeight();
		row->SetDrawArea(drawArea, draggingSplitter_);

		totalHeight += drawArea.Height() + BORDER;
		if (totalHeight > rc.Height())
			break;
		
		tmp = rc;
		tmp.top = drawArea.bottom + BORDER;
		drawArea = tmp;
	}
	
	// calculate draw areas for non fixed rows
	//
	//TRACE1("------------------------------------\n", i - 1);
	for (; i < firstNonFixedRowIndex_ && i < rows_.size(); i++)
		rows_[i]->SetDrawArea(CRect(0,0,0,0), false);

	i = firstNonFixedRowIndex_;
	while ((totalHeight < rc.Height()) && (i < rows_.size())) {
		row = rows_[i];
		
		//TRACE1("updating row %s\n", row->GetCell(0)->GetText().c_str());

		rowHeight = row->GetRowHeight();
		drawArea.bottom = drawArea.top + rowHeight;
		row->SetDrawArea(drawArea, draggingSplitter_);
		row->SetVisible(true);
		//drawArea = row->GetDrawArea();

		totalHeight += rowHeight + BORDER;
				
		drawArea.OffsetRect(0, rowHeight + BORDER);
		
		i++;
	}

	for (; i < rows_.size(); i++)
		rows_[i]->SetDrawArea(CRect(0,0,0,0), false);
}

void CAsTable::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{	
	// Declare variables
	SCROLLINFO si;
	CRect rcClient;
	int newIndex;

	// Setup vertical scrollbar information
	//
	ZeroMemory(&si, sizeof(SCROLLINFO));
	si.cbSize = sizeof(SCROLLINFO);
	si.fMask = SIF_RANGE;

	// Get scrollbar information
	//
	//GetScrollInfo(SB_VERT, &si);

	newIndex = firstNonFixedRowIndex_;
	// Switch scrollbar code
	//
	switch (nSBCode)
	{
		case SB_LINEDOWN:
			firstNonFixedRowIndex_++;
			break;

		case SB_LINEUP:
			firstNonFixedRowIndex_--;
			break;

		case SB_PAGEDOWN:
			firstNonFixedRowIndex_ += vScrollPageSize_;
			break;

		case SB_PAGEUP:
			firstNonFixedRowIndex_ -= vScrollPageSize_;
			break;

		case SB_THUMBTRACK:
			firstNonFixedRowIndex_ = nPos + fixedRowsNumber_;
			break;

		default:
			return;
	}

	// Calculate
	firstNonFixedRowIndex_ = min(vScrollMaxPos_ - vScrollPageSize_ + fixedRowsNumber_ + 1, firstNonFixedRowIndex_);
	firstNonFixedRowIndex_ = max(firstNonFixedRowIndex_, vScrollMinPos_ + fixedRowsNumber_);

	// Set scrollbar info
	si.fMask = SIF_POS;
	si.nPos = firstNonFixedRowIndex_ - fixedRowsNumber_;
	SetScrollInfo(SB_VERT, &si, TRUE);

	UpdateDrawArea();
	
	RedrawWindow();

}

void CAsTable::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	// Declare variables
	SCROLLINFO si;
	CRect rcClient;
	int newIndex;
	CAsTableRow* row;

	// Setup vertical scrollbar information
	//
	ZeroMemory(&si, sizeof(SCROLLINFO));
	si.cbSize = sizeof(SCROLLINFO);
	si.fMask = SIF_RANGE;

	// Get scrollbar information
	//
	row = rows_[0];

	newIndex = row->GetFirstNonFixedColIndex();
	// Switch scrollbar code
	//
	switch (nSBCode)
	{
		case SB_LINEDOWN:
			newIndex++;
			break;

		case SB_LINEUP:
			newIndex--;
			break;

		case SB_PAGEDOWN:
			newIndex += hScrollPageSize_;
			break;

		case SB_PAGEUP:
			newIndex -= hScrollPageSize_;
			break;

		case SB_THUMBTRACK:
			newIndex = nPos + fixedColumnsNumber_;
			break;

		default:
			return;
	}

	// Calculate
	newIndex = min(hScrollMaxPos_ - hScrollPageSize_ + fixedColumnsNumber_ + 1, newIndex);
	newIndex = max(newIndex, vScrollMinPos_ + fixedColumnsNumber_);
	
	for(int i = 0; i < rows_.size(); i++)
		rows_[i]->SetFirstNonFixedColIndex(newIndex);

	// Set scrollbar info
	si.fMask = SIF_POS;
	si.nPos = newIndex - fixedColumnsNumber_;
	SetScrollInfo(SB_HORZ, &si, TRUE);

	UpdateDrawArea();
	
	RedrawWindow();
}

void CAsTable::SetFixedRowsNumber(int number)
{
	fixedRowsNumber_ = number;
	firstNonFixedRowIndex_ = fixedRowsNumber_;
}

int CAsTable::GetFixedRowsNumber() const
{
	return fixedRowsNumber_;
}

void CAsTable::SetFixedColumnsNumber(int number)
{
	fixedColumnsNumber_ = number;

	for (int i = 0; i < rows_.size(); i++)
		rows_[i]->SetFixedColumnsNumber(number);
}

int CAsTable::GetFixedColumnsNumber() const
{
	return fixedColumnsNumber_;
}

int CAsTable::GetNonFixedRowsPerPage()
{
	//return 10;

	CRect rc;
	int i;
	int fixedAreaHeight = 0;
	int variableAreaHeight;
	int rowsPerPage;
	int tmpHeight;
	int rowHeight;
	CAsTableRow* row;

	GetClientRect(rc);
	rc.DeflateRect(BORDER, BORDER, BORDER, BORDER);
	for (i = 0; (i < fixedRowsNumber_) && (i < rows_.size()); i++) {
		row = rows_[i];
		rowHeight = row->GetDrawArea().Height();
		fixedAreaHeight += rowHeight;
		fixedAreaHeight += BORDER;
	}

	variableAreaHeight = rc.Height() - fixedAreaHeight;

	i = firstNonFixedRowIndex_;
	rowsPerPage = 0;
	tmpHeight = 0;
	for (i = firstNonFixedRowIndex_; i < rows_.size(); i++) {
		row = rows_[i];
		rowHeight = row->GetDrawArea().Height();
		if (rowHeight == 0 || tmpHeight + rowHeight > variableAreaHeight)
			break;

		tmpHeight += rowHeight;
		tmpHeight += BORDER;
		rowsPerPage++;
	}
	
	//TRACE1("rows per page = %d\n", rowsPerPage);

	return rowsPerPage;
}

int CAsTable::GetNonFixedColumnsPerPage()
{
	if (rows_.size() == 0)
		return 0;

	CRect rc;
	int i;
	int fixedAreaWidth = 0;
	int variableAreaWidth;
	int columnsPerPage;
	int tmpWidth;
	int cellWidth;
	CAsTableRow* row;
	CAsBaseCell* cell;

	GetClientRect(rc);
	rc.DeflateRect(BORDER, BORDER, BORDER, BORDER);
	
	row = rows_[0];
	
	for (i = 0; (i < fixedColumnsNumber_) && (i < columnsNumber_); i++) {
		cell = row->GetCell(i);
		if (cell == NULL)
			break;

		cellWidth = cell->GetDrawArea().Width();
		fixedAreaWidth += cellWidth;
		fixedAreaWidth += BORDER;
	}

	variableAreaWidth = rc.Width() - fixedAreaWidth;

	
	columnsPerPage = 0;
	tmpWidth = 0;
	for (i = row->GetFirstNonFixedColIndex(); i < columnsNumber_; i++) {
		cell = row->GetCell(i);
		if (cell == NULL)
			break;

		cellWidth = cell->GetDrawArea().Width();
		if (cellWidth == 0 || tmpWidth + cellWidth > variableAreaWidth)
			break;

		tmpWidth += cellWidth;
		tmpWidth += BORDER;
		columnsPerPage++;
	}
	
	//TRACE1("columns per page = %d\n", columnsPerPage);

	return columnsPerPage;
}


void CAsTable::SetColumnWidth(int index, int width)
{
	if (index < 0 || index >= columnsNumber_)
		return;

	colWidth_[index] = width;

	// update all rows
	//
	for (int i = 0; i < rows_.size(); i++)
		rows_[i]->SetColumnWidth(index, width);
}

int CAsTable::GetColumnWidth(int index)
{
	if (index < 0 || index >= columnsNumber_)
		return -1;

	return colWidth_[index];
}

void CAsTable::SetColumnsNumber(int number, int width)
{
	columnsNumber_ = number;

	colWidth_.clear();

	for (int i = 0; i < number; i++)
		colWidth_.push_back(width);
}

int CAsTable::GetColumnsNumber() const
{
	return columnsNumber_;
}

void CAsTable::UpdateFirstNonFixedRowIndex()
{
	CRect rc;
	CRect fixedRowsArea;
	int nonFixedAreaHeight;
	int tmpHeight;
	int i;
	int old;
	
	old = firstNonFixedRowIndex_;
	GetClientRect(rc);
	rc.DeflateRect(0, BORDER, 0, BORDER);
	fixedRowsArea = GetFixedRowsArea();
	
	nonFixedAreaHeight = rc.Height() - fixedRowsArea.Height();
	
	tmpHeight = 0;
	for (i = firstNonFixedRowIndex_; i < rows_.size(); i++) {
		tmpHeight += rows_[i]->GetDrawArea().Height();
		tmpHeight += BORDER;
	}

	if (tmpHeight >= nonFixedAreaHeight)
		return;

	for (i = firstNonFixedRowIndex_ - 1; i >= fixedRowsNumber_; i--) {
		tmpHeight += rows_[i]->GetDrawArea().Height();
		tmpHeight += BORDER;

		if (tmpHeight >= nonFixedAreaHeight)
			break;

		firstNonFixedRowIndex_--;
	}

	if (old != firstNonFixedRowIndex_)
		UpdateDrawArea();

	//TRACE1("new first row = %d\n", firstNonFixedRowIndex_);
}

void CAsTable::UpdateFirstNonFixedColumnIndex()
{
	CRect rc;
	CRect fixedColsArea;
	int nonFixedAreaWidth;
	int tmpWidth;
	int i;
	CAsTableRow* row;
	CAsBaseCell* cell;
	int old;

	if (rows_.size() == NULL)
		return;

	old = firstNonFixedColumnIndex_;
	row = rows_[0];
	
	GetClientRect(rc);
	rc.DeflateRect(BORDER, BORDER, BORDER, BORDER);
	fixedColsArea = GetFixedColsArea();
	
	nonFixedAreaWidth = rc.Width() - fixedColsArea.Width();
	
	tmpWidth = 0;
	firstNonFixedColumnIndex_ = row->GetFirstNonFixedColIndex();
	for (i = firstNonFixedColumnIndex_; i < columnsNumber_; i++) {
		cell = row->GetCell(i);
		if (cell) {
			tmpWidth += cell->GetDrawArea().Width();
			tmpWidth += BORDER;
		}
	}

	if (tmpWidth >= nonFixedAreaWidth)
		return;

	firstNonFixedColumnIndex_ = row->GetFirstNonFixedColIndex();
	for (i = firstNonFixedColumnIndex_ - 1; i >= fixedColumnsNumber_; i--) {
		cell = row->GetCell(i);

		tmpWidth += cell->GetDrawArea().Width();
		tmpWidth += BORDER;

		if (tmpWidth >= nonFixedAreaWidth)
			break;

		firstNonFixedColumnIndex_--;
	}

	//TRACE1("new first column = %d\n", firstNonFixedColumnIndex_);
	if (firstNonFixedColumnIndex_ != old) {
		UpdateDrawArea();
		for (i = 0; i < rows_.size(); i++)
			rows_[i]->SetFirstNonFixedColIndex(firstNonFixedColumnIndex_);
	}
}

CRect CAsTable::GetFixedRowsArea()
{
	CRect area;
	CRect rc;
	CAsTableRow* row;
	int rowHeight;

	GetClientRect(rc);
	area = rc;
	area.bottom = area.top;
	
	for (int i = 0; (i < fixedRowsNumber_) && (i < rows_.size()); i++) {
		row = rows_[i];
		rowHeight = row->GetDrawArea().Height();
		area.bottom += rowHeight;
		area.bottom += BORDER;
	}

	return area;
}

CRect CAsTable::GetFixedColsArea()
{
	CRect area;
	CRect rc;
	CAsTableRow* row;
	CAsBaseCell* cell;
	int colWidth;

	GetClientRect(rc);
	area = rc;
	area.right = area.left;
	
	if (rows_.size() > 0) {
		row = rows_[0];

		for (int i = 0; (i < fixedRowsNumber_) && (i < rows_.size()); i++) {
			cell = row->GetCell(i);
			if (cell) {
				colWidth = cell->GetDrawArea().Width();
				area.right += colWidth;
				area.right += BORDER;
			}
		}
	}

	//TRACE2("fixed cols area topleft(%d, %d)", area.top, area.left);
	//TRACE2(" bottomright(%d, %d)\n", area.bottom, area.right);
	return area;
}

BOOL CAsTable::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{
	CAsTableRow::enTableRowHitTest hitTest;
	CPoint pt;
	int index;

	GetCursorPos(&pt);
	ScreenToClient(&pt);

	for (int i = 0; i < rows_.size(); i++) {
		hitTest = rows_[i]->HitTest(pt, index);

		if (hitTest == CAsTableRow::enTableRowHitTest_Splitter) {
			::SetCursor(::LoadCursor(NULL, IDC_SIZEWE));
			return TRUE;
		}
	}
	
	return CWnd::OnSetCursor(pWnd, nHitTest, message);
}


int CAsTable::HitSplitter(const CPoint& point) 
{
	CAsTableRow::enTableRowHitTest hitTest;
	int splitterIndex;

	for (int i = 0; i < rows_.size(); i++) {
		hitTest = rows_[i]->HitTest(point, splitterIndex);

		splitterRowIndex_ = i;
		if (hitTest == CAsTableRow::enTableRowHitTest_Splitter)
			return splitterIndex;
		
	}

	splitterRowIndex_ = -1;

	return -1;
}

BOOL CAsTable::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) 
{
	if (zDelta > 0) 
		OnVScroll(SB_LINEUP, 0, NULL);
	else if (zDelta < 0)
		OnVScroll(SB_LINEDOWN, 0, NULL);  

	return CWnd::OnMouseWheel(nFlags, zDelta, pt);
}

bool CAsTable::MoveSelection(int horizontalShift, int verticalShift, bool redraw)
{
	CAsTableRow* selRow;		
	CAsBaseCell* selCell;
	bool itemFound;
	int selRowIndex;
	int selCellIndex;
	int newRowIndex;
	int newCellIndex;

	itemFound = GetSelectedItem(&selRow, &selCell, selRowIndex, selCellIndex);

	if (!itemFound)
		return false;

	newRowIndex = selRowIndex + verticalShift;
	newCellIndex = selCellIndex + horizontalShift;

	if (newRowIndex < fixedRowsNumber_ || newRowIndex >= rows_.size())
		return false;

	if (newCellIndex < fixedColumnsNumber_ || newCellIndex >= columnsNumber_)
		return false;

	if (selCell->HasFocus() && horizontalShift != 0)
		return false;

	// kill selection on active cell
	//
	selCell->KillSelection(false);
	
	// get new cell and setfocus
	//
	selRow = rows_[newRowIndex];
	selCell = selRow->GetCell(newCellIndex);
	selCell->SetSelection(false);

	EnsureVisible(newRowIndex, newCellIndex, false);
	
	if (redraw)
		RedrawWindow();

	return true;
}

bool CAsTable::GetFocusedItem(CAsTableRow** row, CAsBaseCell** cell, int& rowIndex, int& cellIndex)
{
	*row = NULL;
	*cell = NULL;

	for (int i = fixedRowsNumber_; i < rows_.size(); i++) {
		*cell = rows_[i]->GetFocusedCell(cellIndex);
		if (*cell) {
			*row = rows_[i];
			rowIndex = i;
			return true;
		}
	}

	return false;
}

bool CAsTable::GetSelectedItem(CAsTableRow** row, CAsBaseCell** cell, int& rowIndex, int& cellIndex)
{
	*row = NULL;
	*cell = NULL;

	for (int i = fixedRowsNumber_; i < rows_.size(); i++) {
		*cell = rows_[i]->GetSelectedCell(cellIndex);
		if (*cell) {
			*row = rows_[i];
			rowIndex = i;
			return true;
		}
	}

	return false;
}

void CAsTable::SetCellFocus(bool redraw)
{
	CAsTableRow* selRow;
	CAsBaseCell* selCell;
	int rowIndex;
	int cellIndex;
	bool itemFound;

	itemFound = GetSelectedItem(&selRow, &selCell, rowIndex, cellIndex);
	if (itemFound)
		selCell->SetFocus(redraw);
}

void CAsTable::KillCellFocus(bool storeData)
{
	CAsTableRow* selRow;
	CAsBaseCell* selCell;
	int rowIndex;
	int cellIndex;
	bool itemFound;

	itemFound = GetFocusedItem(&selRow, &selCell, rowIndex, cellIndex);
	if (itemFound)
		selCell->KillFocus(storeData);
}

void CAsTable::EnsureVisible(int rowIndex, int cellIndex, bool redraw)
{
	firstNonFixedColumnIndex_ = rows_[0]->GetFirstNonFixedColIndex();

	if (rowIndex < firstNonFixedRowIndex_) {
		OnVScroll(SB_LINEUP, 0, NULL);
		return;
	}

	if (rowIndex > firstNonFixedRowIndex_ + GetNonFixedRowsPerPage()) {
		OnVScroll(SB_LINEDOWN, 0, NULL);
		return;
	}

	if (cellIndex < firstNonFixedColumnIndex_) {
		OnHScroll(SB_LINEUP, 0, NULL);
		return;
	}

	if (cellIndex > firstNonFixedColumnIndex_ + GetNonFixedColumnsPerPage() - 1) {
		OnHScroll(SB_LINEDOWN, 0, NULL);
		return;
	}
}

void CAsTable::DeleteNonFixedRows()
{
	if (rows_.size() > fixedRowsNumber_) {
		for (int i = fixedRowsNumber_; i < rows_.size(); i++)
			delete rows_[i];

		rows_.erase(rows_.begin() + fixedRowsNumber_, rows_.end());	
	}
}

void CAsTable::SetBkColor(COLORREF bkColor, bool redraw)
{
	bkColor_ = bkColor;

	if(redraw)
		RedrawWindow();
}

COLORREF CAsTable::GetBkColor() const
{
	return bkColor_;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Italy Italy
For all Stefano's latest code, binaries and tutorials visit www.codemachines.com

Comments and Discussions