//-----------------------------------------------------------------------------
// File: flexcheckbox.cpp
//
// Desc: Implements a check box control similar to Windows check box.
//       CFlexCheckBox is derived from CFlexWnd.  The only place that
//       uses CFlxCheckBox is in the keyboard for sorting by assigned
//       keys.
//
// Copyright (C) 1999-2001 Microsoft Corporation. All Rights Reserved.
//-----------------------------------------------------------------------------

#include "common.hpp"

CFlexCheckBox::CFlexCheckBox() :
	m_hWndNotify(NULL),
	m_bChecked(FALSE),
	m_rgbText(RGB(255,255,255)),
	m_rgbBk(RGB(0,0,0)),
	m_rgbSelText(RGB(0,0,255)),
	m_rgbSelBk(RGB(0,0,0)),
	m_rgbFill(RGB(0,0,255)),
	m_rgbLine(RGB(0,255,255)),
	m_hFont(NULL),
	m_tszText(NULL)
{
}

CFlexCheckBox::~CFlexCheckBox()
{
	delete[] m_tszText;
}

void CFlexCheckBox::SetText(LPCTSTR tszText)
{
	LPTSTR tszTempText = NULL;

	if (tszText)
	{
		tszTempText = new TCHAR[_tcslen(tszText) + 1];
		if (!tszTempText) return;
		_tcscpy(tszTempText, tszText);
	}

	delete[] m_tszText;
	m_tszText = tszTempText;
}

void CFlexCheckBox::SetFont(HFONT hFont)
{
	m_hFont = hFont;

	if (m_hWnd == NULL)
		return;

	Invalidate();
}

void CFlexCheckBox::SetColors(COLORREF text, COLORREF bk, COLORREF seltext, COLORREF selbk, COLORREF fill, COLORREF line)
{
	m_rgbText = text;
	m_rgbBk = bk;
	m_rgbSelText = seltext;
	m_rgbSelBk = selbk;
	m_rgbFill = fill;
	m_rgbLine = line;
	Invalidate();
}

void CFlexCheckBox::SetRect()
{
	if (m_hWnd == NULL)
		return;

	RECT rect = GetRect();
	SetWindowPos(m_hWnd, NULL, rect.left, rect.top, rect.right, rect.bottom, SWP_NOZORDER | SWP_NOMOVE);
}

RECT CFlexCheckBox::GetRect(const RECT &rect)
{
	int h = GetTextHeight(m_hFont);
	RECT ret = {rect.left, rect.top, rect.right, rect.top + h + 2};
	return ret;
}

RECT CFlexCheckBox::GetRect()
{
	RECT rect;
	GetClientRect(&rect);
	return GetRect(rect);
}

void CFlexCheckBox::OnPaint(HDC hDC)
{
	HDC hBDC = NULL, hODC = NULL;
	CBitmap *pbm = NULL;

	if (!InRenderMode())
	{
		hODC = hDC;
		pbm = CBitmap::Create(GetClientSize(), RGB(0,0,0), hDC);
		if (pbm != NULL)
		{
			hBDC = pbm->BeginPaintInto();
			if (hBDC != NULL)
			{
				hDC = hBDC;
			}
		}
	}

	InternalPaint(hDC);

	if (!InRenderMode())
	{
		if (pbm != NULL)
		{
			if (hBDC != NULL)
			{
				pbm->EndPaintInto(hBDC);
				pbm->Draw(hODC);
			}
			delete pbm;
		}
	}
}

void CFlexCheckBox::InternalPaint(HDC hDC)
{
	HGDIOBJ hBrush = (HGDIOBJ)CreateSolidBrush(m_rgbBk);
	if (hBrush != NULL)
	{
		HGDIOBJ hOldBrush = SelectObject(hDC, hBrush);

		// Erase the background first
		RECT client;
		GetClientRect(&client);
		Rectangle(hDC, client.left, client.top, client.right, client.bottom);

		// Create pen for check box
		HGDIOBJ hPen = (HGDIOBJ)CreatePen(PS_SOLID, 1, m_rgbLine);
		if (hPen != NULL)
		{
			HGDIOBJ hOldPen = SelectObject(hDC, hPen);

			RECT rect = {0, 0, 0, 0}, textrc;
			GetClientRect(&rect);
			textrc = rect;
			int iBoxDim = rect.bottom - rect.top;

			// Draw the square box
			rect.right = rect.left + iBoxDim;
			InflateRect(&rect, -2, -2);
			OffsetRect(&rect, 0, -2);  // Move up to align with the text
			Rectangle(hDC, rect.left, rect.top, rect.right, rect.bottom);

			// Draw the check mark if the state is checked.
			if (m_bChecked)
			{
				HGDIOBJ hCrossPen = CreatePen(PS_SOLID, 3, m_rgbLine);
				if (hCrossPen != NULL)
				{
					SelectObject(hDC, hCrossPen);
					MoveToEx(hDC, rect.left + 2, rect.top + 2, NULL);  // Upper left
					LineTo(hDC, rect.right - 2, rect.bottom - 2);  // Lower right
					MoveToEx(hDC, rect.right - 2, rect.top + 2, NULL);  // Upper right
					LineTo(hDC, rect.left + 2, rect.bottom - 2);  // Lower left
					SelectObject(hDC, hPen);
					DeleteObject(hCrossPen);
				}
			}

			SetBkMode(hDC, TRANSPARENT);

			// Draw the message text
			SetTextColor(hDC, m_rgbText);
			textrc.left = rect.right + 8;
			DrawText(hDC, m_tszText, -1, &textrc, DT_LEFT|DT_NOPREFIX|DT_WORDBREAK);

			SelectObject(hDC, hOldPen);
			DeleteObject(hPen);
		}

		SelectObject(hDC, hOldBrush);
		DeleteObject(hBrush);
	}
}

void CFlexCheckBox::Notify(int code)
{
	if (!m_hWndNotify)
		return;

	PostMessage(m_hWndNotify, WM_FLEXCHECKBOX,
		(WPARAM)code, (LPARAM)(LPVOID)this);
}

void CFlexCheckBox::OnClick(POINT point, WPARAM fwKeys, BOOL bLeft)
{
	if (!m_hWnd)
		return;

	RECT rect;
	GetClientRect(&rect);
	rect.right = rect.left + (rect.bottom - rect.top);  // Adjust the width to same as height.
	InflateRect(&rect, -2, -2);
	OffsetRect(&rect, 0, -2);  // Move up to align with the text
	if (PtInRect(&rect, point))
	{
		m_bChecked = !m_bChecked;
		Invalidate();
		Notify(m_bChecked ? CHKNOTIFY_CHECK : CHKNOTIFY_UNCHECK);  // Notify the page object about the state change.
	} else
	{
		// Unhighlight current callout
		HWND hWndParent;
		hWndParent = GetParent(m_hWnd);
		SendMessage(hWndParent, WM_UNHIGHLIGHT, 0, 0);  // Send click message to page to unhighlight callout
	}
}

void CFlexCheckBox::OnMouseOver(POINT point, WPARAM fwKeys)
{
	Notify(CHKNOTIFY_MOUSEOVER);
}
