Click here to Skip to main content
15,896,557 members
Articles / Desktop Programming / MFC

XSuperTooltip - Office 2007 Super Tooltip class

Rate me:
Please Sign up or sign in to vote.
4.98/5 (122 votes)
31 Jul 2006CPOL10 min read 1M   5.4K   240  
XSuperTooltip implements class for displaying super tooltips, which were introduced in Office 2007. The demo download includes super tooltip code generator, that makes it easy to add super tooltips to your application.
// XColourPopup.cpp : implementation file
//
// Written by Chris Maunder (chrismaunder@codeguru.com)
// Extended by Alexander Bischofberger (bischofb@informatik.tu-muenchen.de)
// Copyright (c) 1998.
//
// Updated 30 May 1998 to allow any number of colours, and to
//                     make the appearance closer to Office 97.
//                     Also added "Default" text area.         (CJM)
//
//         13 June 1998 Fixed change of focus bug (CJM)
//         30 June 1998 Fixed bug caused by focus bug fix (D'oh!!)
//                      Solution suggested by Paul Wilkerson.
//
// ColourPopup is a helper class for the colour picker control
// CColourPicker. Check out the header file or the accompanying
// HTML doc file for details.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed unmodified by any means PROVIDING it is
// not sold for profit without the authors written consent, and
// providing that this notice and the authors name is included.
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability if it causes any damage to you or your
// computer whatsoever. It's free, so don't hassle me about it.
//
// Expect bugs.
//
// Please use and enjoy. Please let me know of any bugs/mods/improvements
// that you have found/implemented and I will fix/incorporate them into this
// file.

#include "stdafx.h"
#include <math.h>
#include "XColourPicker.h"
#include "XColourPopup.h"
#include "windowsx.h"		// for GET_X_LPARAM

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

#define DIVIDER_LINE_ROW	9
#define CUSTOM_BUTTON_ROW	10
#define FIRST_CUSTOM_ROW	11


///////////////////////////////////////////////////////////////////////////////
// The following builtin color table is extracted from the complete list of
// X11 colors that are supported by Internet Explorer and Netscape Navigator.
// To see the complete list of colors and color names, read the article by
// Robert Hess at
//        http://www.microsoft.com/workshop/design/color/colorname.asp

ColorTableEntry CXColourPopup::m_crColors[] =
{
	// row 0
	RGB(128,   0,  64), _T("Light Maroon"),        -1,
	RGB(139,   0,   0), _T("Dark Red"),            -1,
	RGB(255,   0,   0), _T("Red"),                 -1,
	RGB(255,   0, 128), _T("Deep Pink"),           -1,
	RGB(255,   0, 255), _T("Magenta"),             -1,
	RGB(255, 128, 192), _T("Pink"),                -1,
	RGB(255, 128, 255), _T("Light Pink"),          -1,
	RGB(255, 208, 232), _T("Very Light Pink"),     -1,

	// row 1
	RGB(255, 140,   0), _T("Dark Orange"),         -1,
	RGB(255, 165,   0), _T("Orange"),              -1,
	RGB(255, 128, 128), _T("Light Salmon"),        -1,
	RGB(255, 224, 160), _T("Light Orange"),        -1,
	RGB(255, 215,   0), _T("Gold"),                -1,
	RGB(255, 255,   0), _T("Yellow"),              -1,
	RGB(255, 255, 128), _T("Desert Yellow"),       -1,
	RGB(255, 255, 184), _T("Pale Yellow"),         -1,

	// row 2
	RGB(  0,  64,   0), _T("Dark Green"),          -1,
	RGB(  0,  64,  64), _T("Medium Green"),        -1,
	RGB(  0, 128,   0), _T("Green"),               -1,
	RGB(  0, 128,  64), _T("Dark Teal"),           -1,
	RGB(128, 128,   0), _T("Olive"),               -1,
	RGB(  0, 128, 128), _T("Teal"),                -1,
	RGB( 64, 128, 128), _T("Turquoise"),           -1,
	RGB(  0, 255,  64), _T("Medium Spring Green"), -1,

	// row 3
	RGB(128, 255,   0), _T("Mint Green"),          -1,
	RGB(  0, 255,   0), _T("Lime"),                -1,
	RGB(  0, 255, 128), _T("Spring Green"),        -1,
	RGB(152, 251, 152), _T("Pale Green"),          -1,
	RGB(127, 255, 212), _T("Aquamarine"),          -1,
	RGB(192, 220, 192), _T("Very Pale Green"),     -1,
	RGB( 64,   0,  64), _T("Deep Purple"),         -1,
	RGB(128,   0, 128), _T("Purple"),              -1,

	// row 4
	RGB( 64,   0, 128), _T("Deep Violet"),         -1,
	RGB(  0,   0,  64), _T("Midnight Blue"),       -1,
	RGB(  0,   0, 160), _T("Dark Blue"),           -1,
	RGB(  0,   0, 128), _T("Navy"),                -1,
	RGB(128,   0, 255), _T("Violet"),              -1,
	RGB(  0,   0, 255), _T("Blue"),                -1,
	RGB(  0,  64, 128), _T("Medium Blue"),         -1,
	RGB(  0, 128, 255), _T("Light Sky Blue"),      -1,

	// row 5
	RGB(100, 149, 237), _T("Cornflower Blue"),     -1,
	RGB(128, 128, 192), _T("Sky Blue"),            -1,
	RGB(  0, 128, 192), _T("Dark Cyan"),           -1,
	RGB(128, 128, 255), _T("Medium Slate Blue"),   -1,
	RGB(128, 255, 255), _T("Light Blue"),          -1,
	RGB(  0, 255, 255), _T("Cyan"),                -1,
	RGB(176, 224, 230), _T("Powder Blue"),         -1,
	RGB(224, 255, 255), _T("Light Cyan"),          -1,

	// row 6
	RGB(  0,   0,   0), _T("Black"),               -1,
	RGB(128, 128, 128), _T("Gray"),                -1,
	RGB(152, 152, 152), _T("Gray 40%"),            -1,
	RGB(192, 192, 192), _T("Silver"),              -1,
	RGB(211, 211, 211), _T("Light Gray"),          -1,
	RGB(245, 245, 220), _T("Beige"),               -1,
	RGB(255, 251, 240), _T("Floral White"),        -1,
	RGB(255, 255, 255), _T("White"),               -1,

	// row 7 - window system colors
	RGB(  0,   0,   0), _T("Window"),              COLOR_WINDOW,
	RGB(  0,   0,   0), _T("WindowText"),          COLOR_WINDOWTEXT,
	RGB(  0,   0,   0), _T("InfoBk"),              COLOR_INFOBK,
	RGB(  0,   0,   0), _T("InfoText"),            COLOR_INFOTEXT,
	RGB(  0,   0,   0), _T("ActiveCaption"),       COLOR_ACTIVECAPTION,
	RGB(  0,   0,   0), _T("CaptionText"),         COLOR_CAPTIONTEXT,
	RGB(  0,   0,   0), _T("InactiveCaption"),     COLOR_INACTIVECAPTION,
	RGB(  0,   0,   0), _T("InactiveCaptionText"), COLOR_INACTIVECAPTIONTEXT,

	// row 8 - window system colors, row #2
	RGB(  0,   0,   0), _T("BtnFace"),             COLOR_BTNFACE,
	RGB(  0,   0,   0), _T("BtnText"),             COLOR_BTNTEXT,
	RGB(  0,   0,   0), _T("BtnShadow"),           COLOR_BTNSHADOW,
	RGB(  0,   0,   0), _T("BtnHighlight"),        COLOR_BTNHIGHLIGHT,
	RGB(  0,   0,   0), _T("Highlight"),           COLOR_HIGHLIGHT,
	RGB(  0,   0,   0), _T("HighlightText"),       COLOR_HIGHLIGHTTEXT,
	RGB(  0,   0,   0), _T("3DLight"),             COLOR_3DLIGHT,
	RGB(  0,   0,   0), _T("Desktop"),             COLOR_DESKTOP,

	// row 9 - divider line
	RGB(192, 192, 192), _T("1"),                   -1,
	RGB(192, 192, 192), _T("2"),                   -1,
	RGB(192, 192, 192), _T("3"),                   -1,
	RGB(192, 192, 192), _T("4"),                   -1,
	RGB(192, 192, 192), _T("5"),                   -1,
	RGB(192, 192, 192), _T("6"),                   -1,
	RGB(192, 192, 192), _T("7"),                   -1,
	RGB(192, 192, 192), _T("8"),                   -1,

	// row 10 - custom button
	RGB(192, 192, 192), _T("9"),                   -1,
	RGB(192, 192, 192), _T("10"),                  -1,
	RGB(192, 192, 192), _T("11"),                  -1,
	RGB(192, 192, 192), _T("12"),                  -1,
	RGB(192, 192, 192), _T("13"),                  -1,
	RGB(192, 192, 192), _T("14"),                  -1,
	RGB(192, 192, 192), _T("15"),                  -1,
	RGB(192, 192, 192), _T("16"),                  -1,

	// custom colors
	// row 11
	(unsigned long)-1, _T("Custom color 1"),       -1,
	(unsigned long)-1, _T("Custom color 2"),       -1,
	(unsigned long)-1, _T("Custom color 3"),       -1,
	(unsigned long)-1, _T("Custom color 4"),       -1,
	(unsigned long)-1, _T("Custom color 5"),       -1,
	(unsigned long)-1, _T("Custom color 6"),       -1,
	(unsigned long)-1, _T("Custom color 7"),       -1,
	(unsigned long)-1, _T("Custom color 8"),       -1,

	// row 12
	(unsigned long)-1, _T("Custom color 9"),       -1,
	(unsigned long)-1, _T("Custom color 10"),      -1,
	(unsigned long)-1, _T("Custom color 11"),      -1,
	(unsigned long)-1, _T("Custom color 12"),      -1,
	(unsigned long)-1, _T("Custom color 13"),      -1,
	(unsigned long)-1, _T("Custom color 14"),      -1,
	(unsigned long)-1, _T("Custom color 15"),      -1,
	(unsigned long)-1, _T("Custom color 16"),      -1
};


/////////////////////////////////////////////////////////////////////////////
// CXColourPopup

BEGIN_MESSAGE_MAP(CXColourPopup, CWnd)
	//{{AFX_MSG_MAP(CXColourPopup)
	ON_WM_NCDESTROY()
	ON_WM_LBUTTONUP()
	ON_WM_PAINT()
	ON_WM_MOUSEMOVE()
	ON_WM_KEYDOWN()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

CXColourPopup::CXColourPopup()
{
	TRACE(_T("in default CXColourPopup::CXColourPopup 1\n"));

	Init();
}

CXColourPopup::CXColourPopup(CWnd * pParentWnd,
						 CPoint p,
						 COLORREF crColor,
						 COLORREF * pCustomColors,
						 int nSelectedRow,
						 int nSelectedCol,
						 LPCTSTR szCustomText /* = NULL */)
{
	TRACE(_T("in CXColourPopup::CXColourPopup 2\n"));

	Init();

	m_nSelectedRow  = nSelectedRow;
	m_nSelectedCol  = nSelectedCol;
	m_crColor       = m_crInitialColor = crColor;
	m_pParent       = pParentWnd;

	TRACE(_T("m_pParent=0x%0X\n"), m_pParent);
	TRACE(_T("setting initial color %08X\n"), m_crInitialColor);

	int i;
	if (nSelectedRow == -1 || nSelectedCol == -1)
	{
		// no selection specified - look thru the color table for a match
		for (i = 0; i < m_nNumColors; i++)
		{
			if (m_crColors[i].crColor == crColor)
			{
				m_nSelectedRow = i / 8;
				m_nSelectedCol = i % 8;
				break;
			}
		}
	}

	if (pCustomColors)
	{
		m_pCustomColors = pCustomColors;

		TRACE(_T("setting custom colors\n"));

		for (i = 0; i < 16; i++)
		{
			m_crColors[FIRST_CUSTOM_ROW * 8 + i].crColor = m_pCustomColors[i];
			TRACE(_T("0x%0X\n"), m_pCustomColors[i]);
		}
	}

	Create(p, crColor, pParentWnd, szCustomText);
}

void CXColourPopup::Init()
{
	m_nNumColors    = sizeof(m_crColors) / sizeof(ColorTableEntry);
	ASSERT(m_nNumColors == 104);
	m_nNumColumns   = 0;
	m_nNumRows      = 0;
	m_nBoxSize      = 18;
	m_nMargin       = ::GetSystemMetrics(SM_CXEDGE);
	m_nCurrentRow   = -1;
	m_nCurrentCol   = -1;
	m_nSelectedRow  = -1;
	m_nSelectedCol  = -1;
	m_crColor       = m_crInitialColor = RGB(255, 255, 255);
	m_pCustomColors = NULL;
	m_bShowCustom   = TRUE;
	m_strCustomText = _T("Custom...");
	m_pParent       = NULL;

	TRACE(_T("setting initial color %08X\n"), m_crInitialColor);

	// Make sure the color square is at least 5 x 5;
	if (m_nBoxSize - 2 * m_nMargin - 2 < 5)
		m_nBoxSize = 5 + 2 * m_nMargin + 2;

	// set system colors
	for (int i = 0; i < m_nNumColors; i++)
		if (m_crColors[i].nSystemColor != -1)
			m_crColors[i].crColor = GetSysColor(m_crColors[i].nSystemColor);
}

CXColourPopup::~CXColourPopup()
{
	if (m_Font.GetSafeHandle())
		m_Font.DeleteObject();
}

///////////////////////////////////////////////////////////////////////////////
// Create
BOOL CXColourPopup::Create(CPoint p,
						 COLORREF crColor,
						 CWnd * pParentWnd,
						 LPCTSTR szCustomText /* = NULL */)
{
	ASSERT(pParentWnd && ::IsWindow(pParentWnd->GetSafeHwnd()));

	m_pParent  = pParentWnd;
	m_crColor  = m_crInitialColor = crColor;

	// Get the class name and create the window
	CString szClassName = AfxRegisterWndClass(
		CS_CLASSDC | CS_SAVEBITS | CS_HREDRAW | CS_VREDRAW,
		0, (HBRUSH)GetStockObject(LTGRAY_BRUSH), 0);

	if (!CWnd::CreateEx(0, szClassName, _T(""), WS_VISIBLE | WS_POPUP,
			p.x, p.y, 100, 100, // size updated soon
		pParentWnd->GetSafeHwnd(), 0, NULL))
	{
		return FALSE;
	}

	// Store the Custom text
	if (szCustomText != NULL)
		m_strCustomText = szCustomText;

	// Set the window size
	SetWindowSize();

	// Create the tooltips
	CreateToolTips();

	// Capture all mouse events for the life of this window
	SetCapture();

	return TRUE;
}

///////////////////////////////////////////////////////////////////////////////
// PreTranslateMessage - for tooltips
BOOL CXColourPopup::PreTranslateMessage(MSG * pMsg)
{
	m_ToolTip.RelayEvent(pMsg);
	return CWnd::PreTranslateMessage(pMsg);
}

///////////////////////////////////////////////////////////////////////////////
// OnKeyDown - if an arrow key is pressed, then move the selection
void CXColourPopup::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	int row = m_nCurrentRow;
	int col = m_nCurrentCol;

	if (row == -1 || col == -1)
	{
		row = m_nSelectedRow;
		col = m_nSelectedCol;
	}

	if (nChar == VK_DOWN)
	{
		row++;
		if (row < 0)
		{
			row = 0;
			col = 0;
		}
		else if (row == DIVIDER_LINE_ROW)
		{
			row++;
		}
		else if (row >= m_nNumRows)
		{
			row = 0;
		}
		ChangeSelection(row, col);
	}

	if (nChar == VK_UP)
	{
		row--;
		if (row < 0)
		{
			row = m_nNumRows - 1;
		}
		else if (row == DIVIDER_LINE_ROW)
		{
			row--;
		}
		ChangeSelection(row, col);
	}

	if (nChar == VK_RIGHT)
	{
		if (col < 0)
		{
			row = 0;
			col = 0;
		}
		else if (col < m_nNumColumns - 1)
		{
			col++;
		}
		else
		{
			col = 0;
		}
		ChangeSelection(row, col);
	}

	if (nChar == VK_LEFT)
	{
		if (col < 0)
		{
			row = m_nNumRows - 1;
			col = m_nNumColumns - 1;
		}
		else if (col > 0)
		{
			col--;
		}
		else
		{
			col = m_nNumColumns - 1;
		}
		ChangeSelection(row, col);
	}

	if (nChar == VK_ESCAPE)
	{
		m_crColor = m_crInitialColor;
		EndSelection(CPN_SELENDCANCEL);
		return;
	}

	if (nChar == VK_RETURN)
	{
		EndSelection(CPN_SELENDOK);
		return;
	}

	CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}

///////////////////////////////////////////////////////////////////////////////
// OnNcDestroy - auto-deletion
void CXColourPopup::OnNcDestroy()
{
	CWnd::OnNcDestroy();
	delete this;
}

///////////////////////////////////////////////////////////////////////////////
// OnPaint
void CXColourPopup::OnPaint()
{
	CPaintDC dc(this); // device context for painting

	// Draw color cells
	for (int row = 0; row < m_nNumRows; row++)
		for (int col = 0; col < m_nNumColumns; col++)
			DrawCell(&dc, row, col);

	// Draw raised window edge (ex-window style WS_EX_WINDOWEDGE is sposed to do this,
	// but for some reason isn't
	CRect rect;
	GetClientRect(rect);
	dc.DrawEdge(rect, EDGE_RAISED, BF_RECT);
}

///////////////////////////////////////////////////////////////////////////////
// OnMouseMove
void CXColourPopup::OnMouseMove(UINT nFlags, CPoint point)
{
	int row, col;

	if (point.x < 0 || point.y < 0)
	{
		ChangeSelection(-1, -1);
		CWnd::OnMouseMove(nFlags, point);
		return;
	}

	// Translate points to be relative raised window edge
	point.x -= m_nMargin;
	point.y -= m_nMargin;

	// First check we aren't in text box
	if (m_bShowCustom && m_TextRect.PtInRect(point))
	{
		row = CUSTOM_BUTTON_ROW;        // Special value meaning Custom button (hack!)
		col = 0;
	}
	else if (m_bShowCustom && m_DividerRect.PtInRect(point))
	{
		row = DIVIDER_LINE_ROW;        // Special value meaning divider line
		col = 0;
	}
	else
	{
		// Get the row and column
		row = point.y / m_nBoxSize,
		col = point.x / m_nBoxSize;

		// In range? If not, default and exit
		if (row < 0 || row >= m_nNumRows || row == DIVIDER_LINE_ROW ||
				col < 0 || col >= m_nNumColumns)
		{
			ChangeSelection(-1, -1);
			CWnd::OnMouseMove(nFlags, point);
			return;
		}
	}

	// OK - we have the row and column of the current selection (may be TEXT_BOX_VALUE)
	// Has the row/col selection changed? If yes, then redraw old and new cells.
	if (row != m_nCurrentRow || col != m_nCurrentCol)
	{
		ChangeSelection(row, col);
	}

	CWnd::OnMouseMove(nFlags, point);
}

///////////////////////////////////////////////////////////////////////////////
// OnLButtonUp - end selection on LButtonUp
void CXColourPopup::OnLButtonUp(UINT nFlags, CPoint point)
{
	TRACE(_T("in CXColourPopup::OnLButtonUp\n"));
	CWnd::OnLButtonUp(nFlags, point);

	DWORD pos = GetMessagePos();
	point = CPoint(GET_X_LPARAM(pos), GET_Y_LPARAM(pos));

	if (m_WindowRect.PtInRect(point))
		EndSelection(CPN_SELENDOK);
	else
		EndSelection(CPN_SELENDCANCEL);
}

///////////////////////////////////////////////////////////////////////////////
// GetCellRect - gets the dimensions of the color cell given by (row,col)
BOOL CXColourPopup::GetCellRect(int row, int col, const LPRECT & rect)
{
	if (row < 0 || row >= m_nNumRows || col < 0 || col >= m_nNumColumns)
		return FALSE;

	rect->left = col * m_nBoxSize + m_nMargin;
	rect->top  = row * m_nBoxSize + m_nMargin;

	rect->right = rect->left + m_nBoxSize;
	rect->bottom = rect->top + m_nBoxSize;

	if (row == DIVIDER_LINE_ROW)
		return FALSE;
	else
		return TRUE;
}

///////////////////////////////////////////////////////////////////////////////
// SetWindowSize - works out an appropriate size and position of this window
void CXColourPopup::SetWindowSize()
{
	CSize TextSize;

	// If we are showing a custom text area, get the font and text size.
	if (m_bShowCustom)
	{
		// Create the font
		if (m_Font.GetSafeHandle() == NULL)
		{
			NONCLIENTMETRICS ncm;
			ncm.cbSize = sizeof(NONCLIENTMETRICS);
			VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
						sizeof(NONCLIENTMETRICS), &ncm, 0));
			m_Font.CreateFontIndirect(&(ncm.lfMessageFont));
		}

		// Get the size of the custom text
		CClientDC dc(this);
		CFont * pOldFont = (CFont *) dc.SelectObject(&m_Font);
		TextSize = dc.GetTextExtent(m_strCustomText)
			+ CSize(2 * m_nMargin, 2 * m_nMargin);
		dc.SelectObject(pOldFont);
	}

	// Get the number of columns and rows
	m_nNumColumns = 8;
	m_nNumRows = (m_nNumColors / m_nNumColumns);
	if (m_nNumColors % m_nNumColumns)
		m_nNumRows++;

	// Get the current window position, and set the new size
	CRect rect;
	GetWindowRect(rect);

	m_WindowRect.SetRect(rect.left, rect.top,
		rect.left + m_nNumColumns * m_nBoxSize + 2 * m_nMargin,
		rect.top + m_nNumRows * m_nBoxSize + 2 * m_nMargin);

	// if custom text, then expand window if necessary, and set text width as
	// window width
	if (m_bShowCustom)
	{
		//m_WindowRect.bottom += (m_nMargin + TextSize.cy);
		if (TextSize.cx > m_WindowRect.Width())
			m_WindowRect.right = m_WindowRect.left + TextSize.cx;
		TextSize.cx = m_WindowRect.Width() - 2 * m_nMargin;

		// Work out the text area
		m_TextRect.SetRect(m_nMargin,
						   m_nMargin + CUSTOM_BUTTON_ROW*m_nBoxSize,
						   m_nMargin + TextSize.cx,
						   m_nMargin + CUSTOM_BUTTON_ROW*m_nBoxSize + TextSize.cy);
		m_DividerRect.SetRect(m_nMargin,
						   m_nMargin + DIVIDER_LINE_ROW*m_nBoxSize,
						   m_nMargin + TextSize.cx,
						   m_nMargin + DIVIDER_LINE_ROW*m_nBoxSize + m_nBoxSize);
	}

	// Set the window size and position
	MoveWindow(m_WindowRect, TRUE);
}

///////////////////////////////////////////////////////////////////////////////
// CreateToolTips
void CXColourPopup::CreateToolTips()
{
	// Create the tool tip
	if (!m_ToolTip.Create(this))
		return;

	// Add a tool for each cell
	for (int row = 0; row < m_nNumRows; row++)
	{
		if (row == DIVIDER_LINE_ROW)
			continue;

		if (row == CUSTOM_BUTTON_ROW)
		{
			m_ToolTip.AddTool(this, _T("Selects a custom color"), m_TextRect, 1);
			continue;
		}

		for (int col = 0; col < m_nNumColumns; col++)
		{
			CRect rect;
			if (!GetCellRect(row, col, rect))
			{
				continue;
			}
			VERIFY(m_ToolTip.AddTool(this, GetColorName(row, col), rect, 1));
		}
	}
}

///////////////////////////////////////////////////////////////////////////////
// ChangeSelection
void CXColourPopup::ChangeSelection(int row, int col)
{
	TRACE(_T("in CXColourPopup::ChangeSelection\n"));

	CClientDC dc(this);        // device context for drawing

	//int row = (row1 < 5) ? row1 : row1 + 1;

	if ((m_nCurrentRow >= 0 && m_nCurrentRow < m_nNumRows &&
			m_nCurrentCol >= 0 && m_nCurrentCol < m_nNumColumns) ||
		(m_nCurrentRow == CUSTOM_BUTTON_ROW) ||
		(m_nCurrentRow == DIVIDER_LINE_ROW))
	{
		// Set Current selection as invalid and redraw old selection (this way
		// the old selection will be drawn unselected)
		int OldRow = m_nCurrentRow;
		int OldCol = m_nCurrentCol;
		m_nCurrentRow = m_nCurrentCol = -1;
		DrawCell(&dc, OldRow, OldCol);
	}

	if (row == -1 || col == -1)
		return;

	// Set the current selection as row/col and draw (it will be drawn selected)
	m_nCurrentRow = row;
	m_nCurrentCol = col;

	if (row == DIVIDER_LINE_ROW)
		return;

	DrawCell(&dc, row, col);

	// Store the current color
	if (m_nCurrentRow == CUSTOM_BUTTON_ROW)// && m_nCurrentCol == TEXT_BOX_VALUE)
	{
		m_pParent->SendMessage(CPN_SELCHANGE, (WPARAM) m_crInitialColor, 0);
	}
	else
	{
		m_crColor = GetColor(m_nCurrentRow, m_nCurrentCol);
		TRACE(_T("setting new color %08X\n"), m_crColor);
		m_pParent->SendMessage(CPN_SELCHANGE, (WPARAM) m_crColor, 0);
	}
}

///////////////////////////////////////////////////////////////////////////////
// EndSelection
void CXColourPopup::EndSelection(int nMessage)
{
	TRACE(_T("in CXColourPopup::EndSelection - m_nCurrentRow=%d\n"), m_nCurrentRow);

	ReleaseCapture();

	if (nMessage != CPN_SELENDCANCEL && m_nCurrentRow == DIVIDER_LINE_ROW)
	{
		// ignore click on divider line
		SetCapture();
		return;
	}
	else if (nMessage != CPN_SELENDCANCEL && m_nCurrentRow == CUSTOM_BUTTON_ROW)
	{
		// if custom text selected, perform a custom color selection
		COLORREF rgb[16];
		int i, row, col;
		for (i = 0, row = FIRST_CUSTOM_ROW; row < FIRST_CUSTOM_ROW+2; row++)
			for (col = 0; col < 8; col++)
				rgb[i++] = GetColor(row, col);

		CColorDialog dlg(m_crInitialColor, CC_FULLOPEN | CC_ANYCOLOR, this);
		dlg.m_cc.lStructSize  = sizeof(CHOOSECOLOR);
		dlg.m_cc.hwndOwner    = m_hWnd;
		dlg.m_cc.lpCustColors = rgb;
		dlg.m_cc.Flags        |= CC_FULLOPEN | CC_ANYCOLOR;

		if (dlg.DoModal() == IDOK)
		{
			m_crColor = dlg.GetColor();
			for (i = 0, row = FIRST_CUSTOM_ROW; row < FIRST_CUSTOM_ROW+2; row++)
				for (col = 0; col < 8; col++)
					SetColor(row, col, rgb[i++]);
			Invalidate();
		}
		SetCapture();
		return;
	}

	if (nMessage == CPN_SELENDCANCEL)
		m_crColor = m_crInitialColor;

	TRACE(_T("m_crColor = %08X =====\n"), m_crColor);

	m_nSelectedRow = m_nCurrentRow;
	m_nSelectedCol = m_nCurrentCol;

	if (m_pCustomColors)
	{
		TRACE(_T("returning custom colors\n"));

		for (int i = 0; i < 16; i++)
		{
			m_pCustomColors[i] = m_crColors[FIRST_CUSTOM_ROW * 8 + i].crColor;
			TRACE(_T("   0x%0X\n"), m_pCustomColors[i]);
		}
	}

	m_pParent->SendMessage(nMessage, (WPARAM) m_crColor,
		MAKELONG((WORD)m_nSelectedRow, (WORD)m_nSelectedCol));

	DestroyWindow();
}

///////////////////////////////////////////////////////////////////////////////
// DrawCell
void CXColourPopup::DrawCell(CDC * pDC, int row, int col)
{
	// This is a special hack for the text box
	if (m_bShowCustom && row == CUSTOM_BUTTON_ROW)// && row == TEXT_BOX_VALUE)
	{
		pDC->FillSolidRect(m_TextRect, ::GetSysColor(COLOR_3DFACE));
		if (m_nCurrentRow == row && m_nCurrentCol == col)
			pDC->DrawEdge(m_TextRect, EDGE_RAISED, BF_RECT);

		// Draw custom text
		CFont * pOldFont = (CFont *) pDC->SelectObject(&m_Font);
		pDC->DrawText(m_strCustomText, m_TextRect,
			DT_CENTER | DT_VCENTER | DT_SINGLELINE);
		pDC->SelectObject(pOldFont);

		return;
	}

	// row/col in range?
	ASSERT(row >= 0 && row < m_nNumRows);
	ASSERT(col >= 0 && col < m_nNumColumns);

	CRect rect;
	if (!GetCellRect(row, col, rect))
	{
		pDC->FillSolidRect(rect, ::GetSysColor(COLOR_3DFACE));
		if (row != DIVIDER_LINE_ROW)
			return;

		// we're trying to draw divider line
		CRect divider(rect);
		int h = divider.Height();
		GetCellRect(row, 7, rect);
		divider.right = rect.right;
		divider.top += (h/2) - 2;
		divider.bottom -= (h/2) - 2;
		UINT nFlags = BF_BOTTOM | BF_TOP;
		if (col == 0)
			nFlags |= BF_LEFT;
		if (col == 7)
			nFlags |= BF_RIGHT;
		pDC->DrawEdge(divider, EDGE_SUNKEN, nFlags);
		return;
	}

	// fill background
	pDC->FillSolidRect(rect, ::GetSysColor(COLOR_3DFACE));

	// Draw raised edge if selected
	if (m_nCurrentRow == row && m_nCurrentCol == col)
		pDC->DrawEdge(rect, EDGE_RAISED, BF_RECT);
	else if (m_nSelectedRow == row && m_nSelectedCol == col)
		pDC->DrawEdge(rect, EDGE_SUNKEN, BF_RECT);

	COLORREF rgbCell = GetColor(row, col);
	if (rgbCell == -1)
		rgbCell = RGB(255, 255, 255);
	CBrush brush(rgbCell);
	CPen pen;
	pen.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW));

	CBrush * pOldBrush = (CBrush *) pDC->SelectObject(&brush);
	CPen * pOldPen = (CPen *) pDC->SelectObject(&pen);

	// Draw the cell color
	rect.DeflateRect(m_nMargin + 1, m_nMargin + 1);
	pDC->Rectangle(rect);

	// restore DC and cleanup
	pDC->SelectObject(pOldBrush);
	pDC->SelectObject(pOldPen);
	brush.DeleteObject();
	pen.DeleteObject();
}

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
Software Developer (Senior) Hans Dietrich Software
United States United States
I attended St. Michael's College of the University of Toronto, with the intention of becoming a priest. A friend in the University's Computer Science Department got me interested in programming, and I have been hooked ever since.

Recently, I have moved to Los Angeles where I am doing consulting and development work.

For consulting and custom software development, please see www.hdsoft.org.






Comments and Discussions