Hi
I havnt been able to work out how to post an attachment, so I have included XSudokuWnd.cpp within this reply - sorry if this isnt the right way to go about this!
The changes that I have made are :
1 Added m_nUnPencil[9][9] to XSudokuWnd.h
2 Defined new popuup menu items ID_POPUP_UNPENCIL_1 - 9 & ID_POPUP_PENCIL_1 - 9, and added in the relevant ON_COMMAND_RANGE to the Message Map
3 Added additional functions OnPopupUnPencil(), OnPopupPencil(), GetUnPenciledCandidates()
4 Altered ShowPopup() function to display Rub Out [x], or Pencil In [X] options.
Again I apologise if I havnt posted this properly - this is my first time!
Mike
<br />
<br />
#include "stdafx.h"<br />
#include "resource.h"<br />
#include "XSudokuWnd.h"<br />
#include "FontSize.h"<br />
#include "dance.h"<br />
#include "memdc.h"<br />
#include "clipboard.h"<br />
#include "GDIUtil.h"<br />
#include "DllInstanceSwitcher.h"<br />
#include "SudokuEntryDlg.h"<br />
#include "ColorPrefDlg.h"<br />
#include "About.h"<br />
<br />
#ifdef _DEBUG<br />
#define new DEBUG_NEW<br />
#undef THIS_FILE<br />
static char THIS_FILE[] = __FILE__;<br />
#endif<br />
<br />
IMPLEMENT_DYNAMIC(CXSudokuWnd,CWnd)<br />
<br />
UINT WM_XSUDOKU = ::RegisterWindowMessage(_T("WM_XSUDOKU"));<br />
<br />
static int g_nGridLineOffset[9] = { 0, 0, 0, 1, 1, 1, 2, 2, 2 };<br />
static TCHAR * g_szDigits = _T("0123456789");<br />
<br />
#define SetBit(x,y) (x|=(1<<(y)))<br />
#define ClearBit(x,y) (x&=~(1<<(y)))<br />
#define TestBit(x,y) (x&(1<<(y)))<br />
<br />
<br />
#define UNDO_ARRAY_GROW_BY_SIZE 20<br />
<br />
#pragma pack(push,1)<br />
struct UNDO_BLOCK<br />
{<br />
UNDO_BLOCK()<br />
{<br />
TRACE(_T("in UNDO_BLOCK()\n"));<br />
action_code = 0;<br />
action_value = 0;<br />
row = col = 0;<br />
};<br />
<br />
BYTE action_code;<br />
#define ACTION_CODE_USER_ENTRY 1 // action_value = 0 to remove user entry<br />
#define ACTION_CODE_USER_ENTRY_REMOVE_ALL 2<br />
#define ACTION_CODE_HINT 3 // action_value: 0 = hide hint; else 1-9<br />
#define ACTION_CODE_HINT_REMOVE_ALL 4<br />
<br />
BYTE action_value;<br />
BYTE row, col;
BYTE hints[9][9];<br />
BYTE user_entries[9][9];<br />
};<br />
#pragma pack(pop)<br />
<br />
<br />
#define ID_POPUP_HIGHLIGHT_0 50000<br />
#define ID_POPUP_HIGHLIGHT_1 50001<br />
#define ID_POPUP_HIGHLIGHT_2 50002<br />
#define ID_POPUP_HIGHLIGHT_3 50003<br />
#define ID_POPUP_HIGHLIGHT_4 50004<br />
#define ID_POPUP_HIGHLIGHT_5 50005<br />
#define ID_POPUP_HIGHLIGHT_6 50006<br />
#define ID_POPUP_HIGHLIGHT_7 50007<br />
#define ID_POPUP_HIGHLIGHT_8 50008<br />
#define ID_POPUP_HIGHLIGHT_9 50009<br />
<br />
#define ID_POPUP_SET_1 50011<br />
#define ID_POPUP_SET_2 50012<br />
#define ID_POPUP_SET_3 50013<br />
#define ID_POPUP_SET_4 50014<br />
#define ID_POPUP_SET_5 50015<br />
#define ID_POPUP_SET_6 50016<br />
#define ID_POPUP_SET_7 50017<br />
#define ID_POPUP_SET_8 50018<br />
#define ID_POPUP_SET_9 50019<br />
<br />
#define ID_POPUP_UNPENCIL_1 50021<br />
#define ID_POPUP_UNPENCIL_2 50022<br />
#define ID_POPUP_UNPENCIL_3 50023<br />
#define ID_POPUP_UNPENCIL_4 50024<br />
#define ID_POPUP_UNPENCIL_5 50025<br />
#define ID_POPUP_UNPENCIL_6 50026<br />
#define ID_POPUP_UNPENCIL_7 50027<br />
#define ID_POPUP_UNPENCIL_8 50028<br />
#define ID_POPUP_UNPENCIL_9 50029<br />
<br />
#define ID_POPUP_PENCIL_1 50051<br />
#define ID_POPUP_PENCIL_2 50052<br />
#define ID_POPUP_PENCIL_3 50053<br />
#define ID_POPUP_PENCIL_4 50054<br />
#define ID_POPUP_PENCIL_5 50055<br />
#define ID_POPUP_PENCIL_6 50056<br />
#define ID_POPUP_PENCIL_7 50057<br />
#define ID_POPUP_PENCIL_8 50058<br />
#define ID_POPUP_PENCIL_9 50059<br />
<br />
#define ID_POPUP_SHOW_HINT 50030<br />
#define ID_POPUP_REMOVE_ALL_HINTS 50031<br />
#define ID_POPUP_SHOW_SOLUTION 50032<br />
#define ID_POPUP_SHOW_PENCIL_MARKS 50033<br />
#define ID_POPUP_RESET 50034<br />
#define ID_POPUP_REMOVE_USER_ENTRY 50035<br />
#define ID_POPUP_REMOVE_ALL_USER_ENTRIES 50036<br />
#define ID_POPUP_CHECK_USER_ENTRIES 50037<br />
#define ID_POPUP_PRINT 50038<br />
#define ID_POPUP_COPY 50039<br />
#define ID_POPUP_UNDO 50040<br />
#define ID_POPUP_REDO 50041<br />
<br />
<br />
BEGIN_MESSAGE_MAP(CXSudokuWnd, CWnd)<br />
ON_WM_ERASEBKGND()<br />
ON_WM_PAINT()<br />
ON_WM_LBUTTONDOWN()<br />
ON_WM_RBUTTONUP()<br />
ON_WM_LBUTTONDBLCLK()<br />
ON_WM_GETDLGCODE()<br />
ON_WM_RBUTTONDOWN()<br />
ON_COMMAND(ID_RIGHT_CLICK, OnRightClick)<br />
ON_COMMAND(ID_COLOR_PREFS, OnColorPrefs)<br />
ON_COMMAND(ID_LOAD_SAMPLE, OnLoadSample)<br />
ON_COMMAND(ID_SHOW_HINT, OnShowHint)<br />
ON_COMMAND(ID_SHOW_SOLUTION, OnShowSolution)<br />
ON_COMMAND(ID_SHOW_PENCIL_MARKS, OnShowPencilMarks)<br />
ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)<br />
ON_COMMAND(ID_EDIT_REDO, OnEditRedo)<br />
ON_COMMAND(ID_EDIT_COPY, OnCopyWindow)<br />
ON_COMMAND(ID_FILE_PRINT, OnPrintWindow)<br />
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)<br />
ON_COMMAND(ID_POPUP_UNDO, OnEditUndo)<br />
ON_COMMAND(ID_POPUP_REDO, OnEditRedo)<br />
ON_COMMAND(ID_POPUP_SHOW_HINT, OnPopupShowHint)<br />
ON_COMMAND(ID_POPUP_REMOVE_ALL_HINTS, OnRemoveAllHints)<br />
ON_COMMAND(ID_POPUP_SHOW_SOLUTION, OnShowSolution)<br />
ON_COMMAND(ID_POPUP_SHOW_PENCIL_MARKS, OnShowPencilMarks)<br />
ON_COMMAND(ID_POPUP_RESET, OnReset)<br />
ON_COMMAND(ID_POPUP_PRINT, OnPrintWindow)<br />
ON_COMMAND(ID_POPUP_COPY, OnCopyWindow)<br />
ON_COMMAND(ID_POPUP_REMOVE_USER_ENTRY, OnRemoveUserEntry)<br />
ON_COMMAND(ID_POPUP_REMOVE_ALL_USER_ENTRIES, OnRemoveAllUserEntries)<br />
ON_COMMAND(ID_POPUP_CHECK_USER_ENTRIES, OnCheckUserEntries)<br />
ON_COMMAND_RANGE(ID_POPUP_SET_1, ID_POPUP_SET_9, OnPopupSet)<br />
ON_COMMAND_RANGE(ID_POPUP_UNPENCIL_1, ID_POPUP_UNPENCIL_9, OnPopupUnPencil)<br />
ON_COMMAND_RANGE(ID_POPUP_PENCIL_1, ID_POPUP_PENCIL_9, OnPopupPencil)<br />
ON_COMMAND_RANGE(ID_POPUP_HIGHLIGHT_1, ID_POPUP_HIGHLIGHT_9, OnPopupHighlight)<br />
ON_COMMAND_RANGE(ID_HIGHLIGHT_0, ID_HIGHLIGHT_9, OnHighlight)<br />
END_MESSAGE_MAP()<br />
<br />
CXSudokuWnd::CXSudokuWnd()<br />
{<br />
m_bIsValid = FALSE;<br />
m_hWndMessage = NULL;<br />
m_hAccel = NULL;<br />
m_bPencilMarks = FALSE;<br />
m_bHaveGivens = FALSE;<br />
m_bShowSolution = FALSE;<br />
m_rgbWindowBackground = RGB(220,20,60);<br />
m_rgbCellBackground = RGB(192,192,192);<br />
m_rgbLabels = RGB(255,255,255);<br />
m_rgbGivens = RGB(220,20,60);<br />
m_rgbSolution = RGB(0, 0, 255);<br />
m_rgbUserEntry = RGB(0, 0, 0);<br />
m_rgbPencilMarks = RGB(0, 0, 128);<br />
m_rgbHighlightNumber = RGB(135, 206, 250);<br />
m_rgbCurCellBorder = RGB(255, 255, 0);<br />
m_rgb3x3Gridline = RGB(0,0,0);<br />
m_strLabelFont = _T("Verdana");<br />
m_nXOffset = 20;<br />
m_nYOffset = 20;<br />
m_nCellWidth = 45;<br />
m_nCellHeight = 44;<br />
m_nHighlightNumber = 0;<br />
m_nCurRow = m_nCurCol = -1;<br />
m_pointPopup = CPoint(-1,-1);<br />
m_strFile = _T("");<br />
<br />
m_bEnableUndo = TRUE;<br />
m_nUndoIndex = 0;<br />
m_nUndoLastEntry = 0;<br />
m_nUndoSize = UNDO_ARRAY_GROW_BY_SIZE;<br />
m_Undo.SetSize(m_nUndoSize);<br />
for (int k = 0; k < m_nUndoSize; k++)<br />
{<br />
UNDO_BLOCK * pUB = new UNDO_BLOCK;<br />
ASSERT(pUB);<br />
m_Undo[k] = pUB;<br />
}<br />
<br />
for (int i = 0; i < 9; i++)<br />
{<br />
for (int j = 0; j < 9; j++)<br />
{<br />
m_nGivens[i][j] = 0;<br />
m_nSolution[i][j] = 0;<br />
m_nHints[i][j] = 0;<br />
m_nUserEntries[i][j] = 0;<br />
}<br />
}<br />
}<br />
<br />
CXSudokuWnd::~CXSudokuWnd()<br />
{<br />
if (m_fontLabels.GetSafeHandle())<br />
m_fontLabels.DeleteObject();<br />
<br />
if (m_fontValues.GetSafeHandle())<br />
m_fontValues.DeleteObject();<br />
<br />
if (m_fontPencilMarks.GetSafeHandle())<br />
m_fontPencilMarks.DeleteObject();<br />
<br />
if (m_fontPrint.GetSafeHandle())<br />
m_fontPrint.DeleteObject();<br />
<br />
for (int j = 0; j < m_nUndoSize; j++)<br />
{<br />
UNDO_BLOCK * pUB = (UNDO_BLOCK *) m_Undo[j];<br />
ASSERT(pUB);<br />
if (pUB)<br />
{<br />
<br />
#ifdef _DEBUG<br />
CString str = ActionCodeToString(pUB->action_code);<br />
if (!str.IsEmpty())<br />
{<br />
TRACE(_T("deleting undo action '%s'\n"), str);<br />
}<br />
#endif<br />
delete pUB;<br />
}<br />
}<br />
}<br />
<br />
UINT CXSudokuWnd::OnGetDlgCode()<br />
{<br />
return DLGC_WANTALLKEYS;<br />
}<br />
<br />
BOOL CXSudokuWnd::OnEraseBkgnd(CDC* pDC)<br />
{<br />
EraseBkgnd(pDC);<br />
return CWnd::OnEraseBkgnd(pDC);<br />
}<br />
<br />
void CXSudokuWnd::EraseBkgnd(CDC* pDC)<br />
{<br />
CRect rect;<br />
GetClientRect(&rect);<br />
pDC->FillSolidRect(rect, m_rgbWindowBackground);<br />
}<br />
<br />
void CXSudokuWnd::OnPaint()<br />
{<br />
CPaintDC dc(this);
<br />
CMemDC memDC(&dc);<br />
<br />
EraseBkgnd(&memDC);<br />
<br />
for (int i = 0; i < 9; i++)<br />
{<br />
for (int j = 0; j < 9; j++)<br />
{<br />
PaintCell(&memDC, i, j);<br />
}<br />
}<br />
<br />
Paint3x3Gridlines(&memDC);<br />
<br />
PaintLabels(&memDC);<br />
<br />
if (m_bHaveGivens)<br />
{<br />
PaintValues(&memDC);<br />
<br />
if (m_bPencilMarks)<br />
PaintPencilMarks(&memDC);<br />
}<br />
<br />
PaintCurCell(&memDC);<br />
<br />
DefWindowProc(WM_PAINT, (WPARAM)memDC->m_hDC, (LPARAM)0);<br />
<br />
}<br />
<br />
CSize CXSudokuWnd::GetWindowSize()<br />
{<br />
CSize size(0, 0);<br />
<br />
size.cx = 2 * m_nXOffset + 9 * (m_nCellWidth+1) + 2;<br />
size.cy = 2 * m_nYOffset + 9 * (m_nCellHeight+1) + 2;<br />
<br />
return size;<br />
}<br />
<br />
COLORREF CXSudokuWnd::GetCellBackgroundColor(int row, int col)<br />
{<br />
COLORREF rgb = m_rgbCellBackground;<br />
<br />
if (m_bHaveGivens && (m_nHighlightNumber != 0))<br />
{<br />
WORD wCandidates = GetCandidates(row, col) & GetUnPenciledCandidates(row, col);
<br />
int nGiven = m_nGivens[row][col];<br />
int nSolution = m_nSolution[row][col];<br />
int nHint = m_nHints[row][col];<br />
int nUserEntry = m_nUserEntries[row][col];<br />
<br />
if (nGiven)<br />
{<br />
if (nGiven == m_nHighlightNumber)<br />
rgb = m_rgbHighlightNumber;<br />
}<br />
else if (nHint)<br />
{<br />
if (nHint == m_nHighlightNumber)<br />
rgb = m_rgbHighlightNumber;<br />
}<br />
else if (nUserEntry)<br />
{<br />
if (nUserEntry == m_nHighlightNumber)<br />
rgb = m_rgbHighlightNumber;<br />
}<br />
else if (nSolution && m_bShowSolution)<br />
{<br />
if (nSolution == m_nHighlightNumber)<br />
rgb = m_rgbHighlightNumber;<br />
}<br />
else if (TestBit(wCandidates, m_nHighlightNumber))<br />
{<br />
rgb = m_rgbHighlightNumber;<br />
}<br />
}<br />
<br />
return rgb;<br />
}<br />
<br />
void CXSudokuWnd::PaintCell(CDC * pDC, int row, int col)<br />
{<br />
CRect rectCell = GetCellRect(row, col);<br />
pDC->FillSolidRect(&rectCell, GetCellBackgroundColor(row, col));<br />
}<br />
<br />
void CXSudokuWnd::Paint3x3Gridlines(CDC * pDC)<br />
{<br />
CPen pen(PS_SOLID, 1, m_rgb3x3Gridline);<br />
<br />
CPen *pOldPen = pDC->SelectObject(&pen);<br />
<br />
CRect rectWnd, rectLine;<br />
GetClientRect(&rectWnd);<br />
rectLine.top = rectWnd.top + m_nYOffset;<br />
rectLine.bottom = rectLine.top + 9 * m_nCellHeight + 8 + 2;<br />
<br />
rectLine.left = rectWnd.left + m_nXOffset + 3 * m_nCellWidth + 2;<br />
pDC->MoveTo(rectLine.left, rectLine.top);<br />
pDC->LineTo(rectLine.left, rectLine.bottom);<br />
pDC->MoveTo(rectLine.left+1, rectLine.top);<br />
pDC->LineTo(rectLine.left+1, rectLine.bottom);<br />
<br />
rectLine.left += 2 + 3 * m_nCellWidth + 2;<br />
pDC->MoveTo(rectLine.left, rectLine.top);<br />
pDC->LineTo(rectLine.left, rectLine.bottom);<br />
pDC->MoveTo(rectLine.left+1, rectLine.top);<br />
pDC->LineTo(rectLine.left+1, rectLine.bottom);<br />
<br />
rectLine.left = rectWnd.left + m_nXOffset;<br />
rectLine.right = rectLine.left + 9 * m_nCellWidth + 8 + 2;<br />
rectLine.top += 3 * m_nCellHeight + 2;<br />
pDC->MoveTo(rectLine.left, rectLine.top);<br />
pDC->LineTo(rectLine.right, rectLine.top);<br />
pDC->MoveTo(rectLine.left, rectLine.top+1);<br />
pDC->LineTo(rectLine.right, rectLine.top+1);<br />
<br />
rectLine.top += 3 * m_nCellHeight + 2 + 2;<br />
pDC->MoveTo(rectLine.left, rectLine.top);<br />
pDC->LineTo(rectLine.right, rectLine.top);<br />
pDC->MoveTo(rectLine.left, rectLine.top+1);<br />
pDC->LineTo(rectLine.right, rectLine.top+1);<br />
<br />
pDC->SelectObject(pOldPen);<br />
}<br />
<br />
void CXSudokuWnd::PaintLabels(CDC * pDC)<br />
{<br />
CFont *pOldFont = pDC->SelectObject(&m_fontLabels);<br />
<br />
pDC->SetBkColor(m_rgbWindowBackground);<br />
pDC->SetTextColor(m_rgbLabels);<br />
<br />
CRect rectWnd, rectLabel;<br />
GetClientRect(&rectWnd);<br />
rectLabel.top = rectWnd.top + m_nYOffset - m_nLabelHeight - 2;<br />
rectLabel.bottom = rectLabel.top + m_nLabelHeight + 2;<br />
rectLabel.left = rectWnd.left + m_nXOffset + m_nCellWidth/2 - 3;<br />
rectLabel.right = rectLabel.left + m_nLabelHeight;<br />
<br />
static TCHAR * szXLabel = _T("ABCDEFGHI");<br />
int i = 0;<br />
for (i = 0; i < 9; i++)<br />
{<br />
rectLabel.left += g_nGridLineOffset[i];<br />
rectLabel.right = rectLabel.left + m_nLabelHeight;<br />
<br />
pDC->ExtTextOut(rectLabel.left, rectLabel.top, <br />
ETO_CLIPPED|ETO_OPAQUE,<br />
&rectLabel,<br />
&szXLabel[i], 1,<br />
NULL);<br />
<br />
rectLabel.left += m_nCellWidth;<br />
}<br />
<br />
rectLabel.top = rectWnd.top + m_nYOffset + m_nCellHeight/2 - 5;<br />
rectLabel.bottom = rectLabel.top + m_nLabelHeight + 2;<br />
rectLabel.left = rectWnd.left + m_nXOffset - m_nLabelHeight - 2;<br />
rectLabel.right = rectLabel.left + m_nLabelHeight;<br />
<br />
for (i = 0; i < 9; i++)<br />
{<br />
rectLabel.top += g_nGridLineOffset[i];<br />
rectLabel.bottom = rectLabel.top + m_nLabelHeight + 1;<br />
<br />
pDC->ExtTextOut(rectLabel.left, rectLabel.top, <br />
ETO_CLIPPED|ETO_OPAQUE,<br />
&rectLabel,<br />
&g_szDigits[i+1], 1,<br />
NULL);<br />
<br />
rectLabel.top += m_nCellHeight;<br />
}<br />
<br />
pDC->SelectObject(pOldFont);<br />
}<br />
<br />
void CXSudokuWnd::PaintValues(CDC * pDC)<br />
{<br />
CFont *pOldFont = pDC->SelectObject(&m_fontValues);<br />
<br />
CSize sizeValue = pDC->GetTextExtent(_T("0"));<br />
int x_offset = m_nCellWidth/2 - sizeValue.cx/2 + 1;<br />
int y_offset = m_nCellHeight/2 - sizeValue.cy/2 + 1;<br />
<br />
for (int i = 0; i < 9; i++)<br />
{<br />
for (int j = 0; j < 9; j++)<br />
{<br />
CRect rectCell = GetCellRect(i, j);<br />
<br />
CRect rectValue;<br />
rectValue.top = rectCell.top + y_offset;<br />
rectValue.bottom = rectValue.top + m_nValueHeight;<br />
rectValue.left = rectCell.left + x_offset;<br />
rectValue.right = rectValue.left + sizeValue.cx;<br />
<br />
pDC->SetBkColor(GetCellBackgroundColor(i, j));<br />
<br />
int nGiven = m_nGivens[i][j];<br />
int nSolution = m_nSolution[i][j];<br />
int nHint = m_nHints[i][j];<br />
int nUserEntry = m_nUserEntries[i][j];<br />
<br />
COLORREF rgbValue;<br />
int nValue;<br />
<br />
if (nGiven)<br />
{<br />
rgbValue = m_rgbGivens;<br />
nValue = nGiven;<br />
}<br />
else if (nHint)<br />
{<br />
rgbValue = m_rgbSolution;<br />
nValue = nHint;<br />
}<br />
else if (nUserEntry)<br />
{<br />
rgbValue = m_rgbUserEntry;<br />
nValue = nUserEntry;<br />
}<br />
else if (nSolution && m_bShowSolution)<br />
{<br />
rgbValue = m_rgbSolution;<br />
nValue = nSolution;<br />
}<br />
else<br />
{<br />
continue;<br />
}<br />
<br />
pDC->SetTextColor(rgbValue);<br />
<br />
pDC->ExtTextOut(rectValue.left, rectValue.top, <br />
ETO_CLIPPED|ETO_OPAQUE,<br />
&rectValue,<br />
&g_szDigits[nValue], 1,<br />
NULL);<br />
}<br />
}<br />
<br />
pDC->SelectObject(pOldFont);<br />
}<br />
<br />
WORD CXSudokuWnd::GetRowCandidates(int row)<br />
{<br />
WORD wBitFlags = 0x3FE;<br />
<br />
for (int col = 0; col < 9; col++)<br />
{<br />
int nGiven = m_nGivens[row][col];<br />
int nHint = m_nHints[row][col];<br />
int nUserEntry = m_nUserEntries[row][col];<br />
<br />
if (nGiven)<br />
{<br />
ClearBit(wBitFlags, nGiven);<br />
}<br />
else if (nHint)<br />
{<br />
ClearBit(wBitFlags, nHint);<br />
}<br />
else if (nUserEntry)<br />
{<br />
ClearBit(wBitFlags, nUserEntry);<br />
}<br />
}<br />
<br />
return wBitFlags;<br />
}<br />
<br />
WORD CXSudokuWnd::GetColCandidates(int col)<br />
{<br />
WORD wBitFlags = 0x3FE;<br />
<br />
for (int row = 0; row < 9; row++)<br />
{<br />
int nGiven = m_nGivens[row][col];<br />
int nHint = m_nHints[row][col];<br />
int nUserEntry = m_nUserEntries[row][col];<br />
<br />
if (nGiven)<br />
{<br />
ClearBit(wBitFlags, nGiven);<br />
}<br />
else if (nHint)<br />
{<br />
ClearBit(wBitFlags, nHint);<br />
}<br />
else if (nUserEntry)<br />
{<br />
ClearBit(wBitFlags, nUserEntry);<br />
}<br />
}<br />
<br />
return wBitFlags;<br />
}<br />
<br />
WORD CXSudokuWnd::GetRegionCandidates(int row, int col)<br />
{<br />
WORD wBitFlags = 0x3FE;<br />
<br />
int nStartRow = (row / 3) * 3;<br />
int nStartCol = (col / 3) * 3;<br />
<br />
for (int i = nStartRow; i < (nStartRow + 3); i++)<br />
{<br />
for (int j = nStartCol; j < (nStartCol + 3); j++)<br />
{<br />
int nGiven = m_nGivens[i][j];<br />
int nHint = m_nHints[i][j];<br />
int nUserEntry = m_nUserEntries[i][j];<br />
<br />
if (nGiven)<br />
{<br />
ClearBit(wBitFlags, nGiven);<br />
}<br />
else if (nHint)<br />
{<br />
ClearBit(wBitFlags, nHint);<br />
}<br />
else if (nUserEntry)<br />
{<br />
ClearBit(wBitFlags, nUserEntry);<br />
}<br />
}<br />
}<br />
<br />
return wBitFlags;<br />
}<br />
<br />
<br />
WORD CXSudokuWnd::GetUnPenciledCandidates(int row, int col)<br />
{<br />
return (~m_nUnPencil[row][col])&0x3FE; <br />
}<br />
<br />
WORD CXSudokuWnd::GetCandidates(int row, int col)<br />
{<br />
WORD wRowCandidates = GetRowCandidates(row);<br />
WORD wColCandidates = GetColCandidates(col);<br />
WORD wRegionCandidates = GetRegionCandidates(row, col);<br />
<br />
WORD wBitFlags = (WORD) (wRowCandidates & wColCandidates & wRegionCandidates);
<br />
TRACE(_T("Candidates for %d,%d: 0x%X\n"), row, col, wBitFlags);<br />
<br />
return wBitFlags;<br />
}<br />
<br />
CRect CXSudokuWnd::GetCellRect(int row, int col)<br />
{<br />
CRect rectCell, rectWnd;<br />
GetClientRect(&rectWnd);<br />
<br />
rectCell.left = rectWnd.left + m_nXOffset + col * (m_nCellWidth + 1);<br />
rectCell.left += g_nGridLineOffset[col];<br />
rectCell.right = rectCell.left + m_nCellWidth;<br />
<br />
rectCell.top = rectWnd.top + m_nYOffset + row * (m_nCellHeight + 1);<br />
rectCell.top += g_nGridLineOffset[row];<br />
rectCell.bottom = rectCell.top + m_nCellHeight;
<br />
return rectCell;<br />
}<br />
<br />
void CXSudokuWnd::PaintPencilMarks(CDC * pDC)<br />
{<br />
CFont *pOldFont = pDC->SelectObject(&m_fontPencilMarks);<br />
<br />
pDC->SetTextColor(m_rgbPencilMarks);<br />
<br />
int nXOffset = ((m_nCellWidth - (3 * m_nLabelHeight)) / 2) + 2;<br />
<br />
for (int i = 0; i < 9; i++)<br />
{<br />
for (int j = 0; j < 9; j++)<br />
{<br />
pDC->SetBkColor(GetCellBackgroundColor(i, j));<br />
<br />
int nGiven = m_nGivens[i][j];<br />
int nSolution = m_nSolution[i][j];<br />
int nHint = m_nHints[i][j];<br />
int nUserEntry = m_nUserEntries[i][j];<br />
<br />
if (nGiven || nUserEntry || nHint || (nSolution && m_bShowSolution))<br />
continue;<br />
<br />
WORD wCandidates = GetCandidates(i, j) & GetUnPenciledCandidates(i, j);<br />
<br />
CRect rectCell = GetCellRect(i, j);<br />
<br />
CRect rectPencilMarks;<br />
rectPencilMarks.left = rectCell.left + nXOffset;<br />
rectPencilMarks.right = rectPencilMarks.left + m_nLabelHeight + 2;<br />
<br />
for (int nCandidate = 1; nCandidate <= 9; nCandidate++)<br />
{<br />
rectPencilMarks.top = rectCell.top + 3 + ((nCandidate-1)/3) * (m_nLabelHeight+1);<br />
rectPencilMarks.bottom = rectPencilMarks.top + m_nLabelHeight + 2;<br />
<br />
if (TestBit(wCandidates, nCandidate))<br />
{<br />
pDC->ExtTextOut(rectPencilMarks.left, rectPencilMarks.top, <br />
ETO_CLIPPED|ETO_OPAQUE,<br />
&rectPencilMarks,<br />
&g_szDigits[nCandidate], 1,<br />
NULL);<br />
}<br />
if (nCandidate == 3 || nCandidate == 6)<br />
rectPencilMarks.left = rectCell.left + nXOffset;<br />
else<br />
rectPencilMarks.left += m_nLabelHeight;<br />
<br />
rectPencilMarks.right = rectPencilMarks.left + m_nLabelHeight + 2;<br />
}<br />
}<br />
}<br />
<br />
pDC->SelectObject(pOldFont);<br />
}<br />
<br />
void CXSudokuWnd::PaintCurCell(CDC * pDC)<br />
{<br />
if ((m_nCurRow != -1) && (m_nCurCol != -1))<br />
{<br />
CRect rectCell = GetCellRect(m_nCurRow, m_nCurCol);<br />
<br />
CPen pen(PS_SOLID, 1, m_rgbCurCellBorder);<br />
<br />
CPen *pOldPen = pDC->SelectObject(&pen);<br />
<br />
pDC->MoveTo(rectCell.left, rectCell.top);<br />
pDC->LineTo(rectCell.right, rectCell.top);<br />
pDC->MoveTo(rectCell.left, rectCell.top+1);<br />
pDC->LineTo(rectCell.right, rectCell.top+1);<br />
pDC->MoveTo(rectCell.left, rectCell.top+2);<br />
pDC->LineTo(rectCell.right, rectCell.top+2);<br />
<br />
pDC->MoveTo(rectCell.left, rectCell.bottom-3);<br />
pDC->LineTo(rectCell.right, rectCell.bottom-3);<br />
pDC->MoveTo(rectCell.left, rectCell.bottom-2);<br />
pDC->LineTo(rectCell.right, rectCell.bottom-2);<br />
pDC->MoveTo(rectCell.left, rectCell.bottom-1);<br />
pDC->LineTo(rectCell.right, rectCell.bottom-1);<br />
<br />
pDC->MoveTo(rectCell.left, rectCell.top);<br />
pDC->LineTo(rectCell.left, rectCell.bottom);<br />
pDC->MoveTo(rectCell.left+1, rectCell.top);<br />
pDC->LineTo(rectCell.left+1, rectCell.bottom);<br />
pDC->MoveTo(rectCell.left+2, rectCell.top);<br />
pDC->LineTo(rectCell.left+2, rectCell.bottom);<br />
<br />
pDC->MoveTo(rectCell.right-1, rectCell.top);<br />
pDC->LineTo(rectCell.right-1, rectCell.bottom);<br />
pDC->MoveTo(rectCell.right-2, rectCell.top);<br />
pDC->LineTo(rectCell.right-2, rectCell.bottom);<br />
pDC->MoveTo(rectCell.right-3, rectCell.top);<br />
pDC->LineTo(rectCell.right-3, rectCell.bottom);<br />
<br />
pDC->SelectObject(pOldPen);<br />
}<br />
}<br />
<br />
BOOL CXSudokuWnd::CellFromPoint(CPoint point, int& nRow, int& nCol)<br />
{<br />
nRow = nCol = -1;<br />
<br />
BOOL bCellFound = FALSE;<br />
<br />
CRect rectCell;<br />
<br />
for (int i = 0; i < 9; i++)<br />
{<br />
for (int j = 0; j < 9; j++)<br />
{<br />
rectCell = GetCellRect(i, j);<br />
if (rectCell.PtInRect(point))<br />
{<br />
nRow = i;<br />
nCol = j;<br />
bCellFound = TRUE;<br />
break;<br />
}<br />
}<br />
if (bCellFound)<br />
break;<br />
}<br />
<br />
return bCellFound;<br />
}<br />
<br />
void CXSudokuWnd::OnLButtonDown(UINT nFlags, CPoint point)<br />
{<br />
TRACE(_T("in CXSudokuWnd::OnLButtonDown\n"));<br />
<br />
<br />
int nOldRow = m_nCurRow;<br />
int nOldCol = m_nCurCol;<br />
<br />
if (CellFromPoint(point, m_nCurRow, m_nCurCol))<br />
{<br />
if ((nOldRow != -1) && (nOldCol != -1))<br />
{<br />
CRect rectOld = GetCellRect(nOldRow, nOldCol);<br />
InvalidateRect(&rectOld, FALSE);<br />
}<br />
CRect rectNew = GetCellRect(m_nCurRow, m_nCurCol);<br />
InvalidateRect(&rectNew, FALSE);<br />
SetFocus();<br />
}<br />
<br />
CWnd::OnLButtonDown(nFlags, point);<br />
}<br />
<br />
void CXSudokuWnd::OnLButtonDblClk(UINT nFlags, CPoint point)<br />
{<br />
TRACE(_T("in CXSudokuWnd::OnLButtonDblClk\n"));<br />
<br />
ShowPopup(point);<br />
<br />
CWnd::OnLButtonDblClk(nFlags, point);<br />
}<br />
<br />
void CXSudokuWnd::OnRButtonDown(UINT nFlags, CPoint point)<br />
{<br />
<br />
int nOldRow = m_nCurRow;<br />
int nOldCol = m_nCurCol;<br />
<br />
if (CellFromPoint(point, m_nCurRow, m_nCurCol))<br />
{<br />
if ((nOldRow != -1) && (nOldCol != -1))<br />
{<br />
CRect rectOld = GetCellRect(nOldRow, nOldCol);<br />
InvalidateRect(&rectOld, FALSE);<br />
}<br />
CRect rectNew = GetCellRect(m_nCurRow, m_nCurCol);<br />
InvalidateRect(&rectNew, FALSE);<br />
SetFocus();<br />
}<br />
<br />
CWnd::OnRButtonDown(nFlags, point);<br />
}<br />
<br />
void CXSudokuWnd::OnRButtonUp(UINT nFlags, CPoint point)<br />
{<br />
ShowPopup(point);<br />
<br />
CWnd::OnRButtonUp(nFlags, point);<br />
}<br />
<br />
BOOL CXSudokuWnd::PreTranslateMessage(MSG* pMsg)<br />
{<br />
switch (pMsg->message)<br />
{<br />
case WM_KEYUP:<br />
if ((pMsg->wParam >= _T('0')) && (pMsg->wParam <= _T('9')))<br />
{<br />
if ((m_nCurRow != -1) &&<br />
(m_nCurCol != -1) &&<br />
(m_nGivens[m_nCurRow][m_nCurCol] == 0))<br />
{<br />
WORD wCandidates = GetCandidates(m_nCurRow, m_nCurCol) & GetUnPenciledCandidates(m_nCurRow, m_nCurCol);<br />
int nDigit = pMsg->wParam - _T('0');<br />
if (nDigit && TestBit(wCandidates, nDigit))<br />
{<br />
SWITCH_RESOURCE;
<br />
AddUndoAction(m_nCurRow, m_nCurCol, ACTION_CODE_USER_ENTRY, nDigit);<br />
m_nUserEntries[m_nCurRow][m_nCurCol] = nDigit;<br />
CString str = _T("");<br />
CString strColumns = _T("");<br />
VERIFY(strColumns.LoadString(IDS_COLUMN_LABELS));<br />
str.Format(IDS_USER_ENTRY, nDigit, m_nCurRow+1, strColumns[m_nCurCol]);<br />
int nType = 0;<br />
CString strCorrect = _T("");<br />
if (nDigit == m_nSolution[m_nCurRow][m_nCurCol])<br />
{<br />
VERIFY(strCorrect.LoadString(IDS_CORRECT));<br />
}<br />
else<br />
{<br />
VERIFY(strCorrect.LoadString(IDS_INCORRECT));<br />
nType = 1;<br />
}<br />
str += strCorrect;<br />
<br />
if (m_hWndMessage && ::IsWindow(m_hWndMessage))<br />
::SendMessage(m_hWndMessage, WM_XSUDOKU, nType,<br />
(LPARAM)(LPCTSTR)str);<br />
}<br />
else if (nDigit == 0)<br />
{<br />
AddUndoAction(m_nCurRow, m_nCurCol, ACTION_CODE_USER_ENTRY, nDigit);<br />
m_nUserEntries[m_nCurRow][m_nCurCol] = nDigit;<br />
}<br />
<br />
m_nHints[m_nCurRow][m_nCurCol] = 0;<br />
Invalidate(FALSE);<br />
}<br />
return TRUE;<br />
}<br />
else if (pMsg->wParam == VK_RETURN)<br />
{<br />
OnRightClick();<br />
}<br />
break;<br />
<br />
case WM_KEYDOWN:<br />
int nOldRow = m_nCurRow;<br />
int nOldCol = m_nCurCol;<br />
BOOL bUpdate = FALSE;<br />
switch (pMsg->wParam)<br />
{<br />
case VK_DOWN:<br />
TRACE(_T("VK_DOWN\n"));<br />
<br />
if (m_nCurRow < 8)<br />
{<br />
m_nCurRow++;<br />
bUpdate = TRUE;<br />
}<br />
break;<br />
<br />
case VK_UP:<br />
TRACE(_T("VK_UP\n"));<br />
<br />
if (m_nCurRow > 0)<br />
{<br />
m_nCurRow--;<br />
bUpdate = TRUE;<br />
}<br />
break;<br />
<br />
case VK_RIGHT:<br />
TRACE(_T("VK_RIGHT\n"));<br />
<br />
if (m_nCurCol < 8)<br />
{<br />
m_nCurCol++;<br />
bUpdate = TRUE;<br />
}<br />
break;<br />
<br />
case VK_LEFT:<br />
TRACE(_T("VK_LEFT\n"));<br />
<br />
if (m_nCurCol > 0)<br />
{<br />
m_nCurCol--;<br />
bUpdate = TRUE;<br />
}<br />
break;<br />
<br />
case VK_HOME:<br />
TRACE(_T("VK_HOME\n"));<br />
<br />
if (m_nCurCol > 0)<br />
{<br />
m_nCurCol = 0;<br />
bUpdate = TRUE;<br />
}<br />
break;<br />
<br />
case VK_END:<br />
TRACE(_T("VK_END\n"));<br />
<br />
if (m_nCurCol < 8)<br />
{<br />
m_nCurCol = 8;<br />
bUpdate = TRUE;<br />
}<br />
break;<br />
<br />
case VK_PRIOR:<br />
TRACE(_T("VK_PRIOR\n"));<br />
<br />
if (m_nCurRow > 0)<br />
{<br />
m_nCurRow = 0;<br />
bUpdate = TRUE;<br />
}<br />
break;<br />
<br />
case VK_NEXT:<br />
TRACE(_T("VK_NEXT\n"));<br />
<br />
if (m_nCurRow < 8)<br />
{<br />
m_nCurRow = 8;<br />
bUpdate = TRUE;<br />
}<br />
break;<br />
<br />
}<br />
<br />
if (bUpdate)<br />
{<br />
if ((nOldRow != -1) && (nOldCol != -1))<br />
{<br />
CRect rectOld = GetCellRect(nOldRow, nOldCol);<br />
InvalidateRect(&rectOld, FALSE);<br />
}<br />
CRect rectNew = GetCellRect(m_nCurRow, m_nCurCol);<br />
InvalidateRect(&rectNew, FALSE);<br />
SetFocus();<br />
}<br />
break;<br />
}<br />
<br />
if (m_hAccel && ::TranslateAccelerator(m_hWnd, m_hAccel, pMsg))<br />
return TRUE;<br />
<br />
return CWnd::PreTranslateMessage(pMsg);<br />
}<br />
<br />
BOOL CXSudokuWnd::Create(LPCTSTR lpszClassName,<br />
LPCTSTR lpszWindowName,<br />
DWORD dwStyle,<br />
const RECT& rect,<br />
CWnd* pParentWnd,<br />
UINT nID,<br />
CCreateContext* pContext)<br />
{<br />
TRACE(_T("in CXSudokuWnd::Create\n"));<br />
BOOL bRet = CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect,<br />
pParentWnd, nID, pContext);<br />
<br />
if (bRet)<br />
{<br />
SWITCH_RESOURCE;
<br />
m_hAccel = ::LoadAccelerators(ExtensionDLL.hModule, <br />
MAKEINTRESOURCE(IDR_ACCELERATOR));<br />
ASSERT(m_hAccel);<br />
<br />
<br />
LOGFONT lf;<br />
memset(&lf, 0, sizeof(lf));<br />
CFont *pFont = GetFont();<br />
if (pFont == NULL)<br />
pFont = GetParent()->GetFont();<br />
pFont->GetLogFont(&lf);<br />
_tcscpy(lf.lfFaceName, m_strLabelFont);<br />
lf.lfWeight = FW_BOLD;<br />
<br />
m_nLabelHeight = abs(lf.lfHeight);<br />
<br />
if (m_fontLabels.GetSafeHandle())<br />
m_fontLabels.DeleteObject();<br />
<br />
m_fontLabels.CreateFontIndirect(&lf);<br />
<br />
lf.lfWeight = FW_NORMAL;<br />
<br />
if (m_fontPencilMarks.GetSafeHandle())<br />
m_fontPencilMarks.DeleteObject();<br />
<br />
m_fontPencilMarks.CreateFontIndirect(&lf);<br />
<br />
lf.lfWeight = FW_BOLD;<br />
_tcscpy(lf.lfFaceName, _T("Arial"));<br />
lf.lfHeight = GetFontHeight(30);<br />
m_nValueHeight = abs(lf.lfHeight);<br />
<br />
if (m_fontValues.GetSafeHandle())<br />
m_fontValues.DeleteObject();<br />
<br />
m_fontValues.CreateFontIndirect(&lf);<br />
<br />
SetFocus();<br />
}<br />
<br />
return bRet;<br />
}<br />
<br />
CString CXSudokuWnd::GetSudoku(LPCTSTR lpszPuzzle )<br />
{<br />
SWITCH_RESOURCE;
<br />
CString strSudoku = _T("");<br />
<br />
CSudokuEntryDlg dlg;<br />
<br />
if (lpszPuzzle)<br />
dlg.m_strSudoku = lpszPuzzle;<br />
<br />
if (dlg.DoModal() == IDOK)<br />
{<br />
strSudoku = dlg.m_strSudoku;<br />
}<br />
<br />
return strSudoku;<br />
}<br />
<br />
void CXSudokuWnd::Reset(BOOL bResetAll)<br />
{<br />
m_nCurRow = m_nCurCol = -1;<br />
m_pointPopup = CPoint(-1,-1);<br />
m_bShowSolution = FALSE;<br />
if (bResetAll)<br />
m_bIsValid = FALSE;<br />
<br />
for (int i = 0; i < 9; i++)<br />
{<br />
for (int j = 0; j < 9; j++)<br />
{<br />
m_nHints[i][j] = 0;<br />
m_nUserEntries[i][j] = 0;<br />
if (bResetAll)<br />
{<br />
m_nGivens[i][j] = 0;<br />
m_nUnPencil[i][j] = 0;<br />
m_nSolution[i][j] = 0;<br />
}<br />
}<br />
}<br />
<br />
m_nUndoIndex = 0;<br />
m_nUndoLastEntry = 0;<br />
<br />
for (int k = 0; k < m_nUndoSize; k++)<br />
{<br />
UNDO_BLOCK * pUB = (UNDO_BLOCK *) m_Undo[k];<br />
ASSERT(pUB);<br />
if (pUB)<br />
{<br />
pUB->action_code = 0;<br />
pUB->action_value = 0;<br />
}<br />
}<br />
}<br />
<br />
BOOL CXSudokuWnd::LoadFromFile(LPCTSTR lpszFile)<br />
{<br />
BOOL ok = FALSE;<br />
<br />
ASSERT(lpszFile && (lpszFile[0] != _T('\0')));<br />
if (lpszFile && (lpszFile[0] != _T('\0')))<br />
{<br />
CFile file;<br />
if (file.Open(lpszFile, CFile::shareDenyNone | CFile::modeRead))<br />
{<br />
m_strFile = lpszFile;<br />
<br />
DWORD dwLen = file.GetLength();
<br />
if (dwLen > 2000)<br />
dwLen = 2000;<br />
<br />
if (dwLen)<br />
{<br />
TCHAR * buf = new TCHAR [dwLen+10];<br />
memset(buf, 0, (dwLen+10) * sizeof(TCHAR));<br />
<br />
file.Read(buf, dwLen);<br />
<br />
ok = LoadFromString(buf, dwLen/sizeof(TCHAR));<br />
<br />
delete [] buf;<br />
}<br />
<br />
file.Close();<br />
}<br />
}<br />
<br />
return ok;<br />
}<br />
<br />
BOOL CXSudokuWnd::LoadFromClipboard()<br />
{<br />
BOOL ok = FALSE;<br />
<br />
m_strFile = _T("");<br />
<br />
CClipboard clip;<br />
DWORD dwLen = clip.GetTextLength();
TRACE(_T("dwLen=%d\n"), dwLen);<br />
<br />
if (dwLen > 2000)<br />
dwLen = 2000;<br />
<br />
if (dwLen)<br />
{<br />
TCHAR * buf = new TCHAR [dwLen+10];<br />
memset(buf, 0, (dwLen+10) * sizeof(TCHAR));<br />
<br />
clip.GetText(buf, dwLen+2);<br />
<br />
ok = LoadFromString(buf, dwLen/sizeof(TCHAR));<br />
<br />
delete [] buf;<br />
}<br />
<br />
return ok;<br />
}<br />
<br />
BOOL CXSudokuWnd::LoadFromString(LPCTSTR lpszString, DWORD dwLen)<br />
{<br />
BOOL ok = FALSE;<br />
<br />
Reset(TRUE);<br />
<br />
TRACE(_T("dwLen=%d\n"), dwLen);<br />
int nCount = 0;
<br />
ASSERT(dwLen);<br />
ASSERT(lpszString && (lpszString[0] != _T('\0')));<br />
<br />
if ((dwLen >= 81) && lpszString && (lpszString[0] != _T('\0')))<br />
{<br />
TRACE(_T("lpszString=<%s>\n"), lpszString);<br />
<br />
int row = 0;<br />
int col = 0;<br />
<br />
for (DWORD dwIndex = 0; dwIndex < dwLen; dwIndex++)<br />
{<br />
TCHAR c = lpszString[dwIndex];<br />
<br />
int nValue = 0;<br />
<br />
if (c == _T('\0'))
break;<br />
<br />
if (c == _T('.'))
{<br />
nValue = 0;<br />
}<br />
else if (_istdigit(c))<br />
{<br />
nValue = c - _T('0');<br />
}<br />
else<br />
{<br />
continue;<br />
}<br />
<br />
m_nGivens[row][col++] = nValue;<br />
nCount++;<br />
if (nCount == 81)<br />
break;<br />
if (col >= 9)<br />
{<br />
row++;<br />
col = 0;<br />
}<br />
}
}<br />
<br />
TRACE(_T("nCount=%d\n"), nCount);<br />
<br />
if (nCount == 81)<br />
{<br />
m_bHaveGivens = TRUE;<br />
<br />
memcpy(m_nSolution, m_nGivens, sizeof(m_nSolution));<br />
<br />
DLX dlx;<br />
int n = dlx.sudoku_solve(m_nSolution);<br />
<br />
SWITCH_RESOURCE;
<br />
int nType = 0;<br />
CString str = _T("");<br />
if (n == 0)<br />
{<br />
nType = 1;<br />
VERIFY(str.LoadString(IDS_SUDOKU_UNSOLVABLE));<br />
}<br />
else if (n == 1)<br />
{<br />
VERIFY(str.LoadString(IDS_SUDOKU_OK));<br />
m_bIsValid = TRUE;<br />
}<br />
else<br />
{<br />
nType = 1;<br />
VERIFY(str.LoadString(IDS_SUDOKU_INVALID));<br />
}<br />
if (m_hWndMessage && ::IsWindow(m_hWndMessage))<br />
::SendMessage(m_hWndMessage, WM_XSUDOKU, nType,<br />
(LPARAM)(LPCTSTR)str);<br />
<br />
ok = TRUE;<br />
}<br />
<br />
return ok;<br />
}<br />
<br />
BOOL CXSudokuWnd::ShowColorPrefsDlg()<br />
{<br />
SWITCH_RESOURCE;
<br />
BOOL ok = FALSE;<br />
<br />
CColorPrefDlg dlg;<br />
<br />
dlg.m_rgbWindowBackground = m_rgbWindowBackground;<br />
dlg.m_rgbCellBackground = m_rgbCellBackground;<br />
dlg.m_rgbLabels = m_rgbLabels;<br />
dlg.m_rgbGivens = m_rgbGivens;<br />
dlg.m_rgbSolution = m_rgbSolution;<br />
dlg.m_rgbUserEntry = m_rgbUserEntry;<br />
dlg.m_rgbPencilMarks = m_rgbPencilMarks;<br />
dlg.m_rgbHighlightNumber = m_rgbHighlightNumber;<br />
dlg.m_rgbCurCellBorder = m_rgbCurCellBorder;<br />
dlg.m_rgb3x3Gridline = m_rgb3x3Gridline;<br />
<br />
if (dlg.DoModal() == IDOK)<br />
{<br />
m_rgbWindowBackground = dlg.m_rgbWindowBackground;<br />
m_rgbCellBackground = dlg.m_rgbCellBackground;<br />
m_rgbLabels = dlg.m_rgbLabels;<br />
m_rgbGivens = dlg.m_rgbGivens;<br />
m_rgbSolution = dlg.m_rgbSolution;<br />
m_rgbUserEntry = dlg.m_rgbUserEntry;<br />
m_rgbPencilMarks = dlg.m_rgbPencilMarks;<br />
m_rgbHighlightNumber = dlg.m_rgbHighlightNumber;<br />
m_rgbCurCellBorder = dlg.m_rgbCurCellBorder;<br />
m_rgb3x3Gridline = dlg.m_rgb3x3Gridline;<br />
<br />
Invalidate(FALSE);<br />
<br />
ok = TRUE;<br />
}<br />
<br />
return ok;<br />
}<br />
<br />
BOOL CXSudokuWnd::CaptureBitmap()<br />
{<br />
CDC dc;<br />
HDC hdc = ::GetDC(m_hWnd);<br />
dc.Attach(hdc);<br />
<br />
CDC memDC;<br />
memDC.CreateCompatibleDC(&dc);<br />
<br />
CBitmap bm;<br />
CRect r;<br />
GetClientRect(&r);<br />
<br />
CSize sz(r.Width(), r.Height());<br />
bm.CreateCompatibleBitmap(&dc, sz.cx, sz.cy);<br />
CBitmap * oldbm = memDC.SelectObject(&bm);<br />
memDC.BitBlt(0, 0, sz.cx, sz.cy, &dc, 0, 0, SRCCOPY);<br />
<br />
BOOL bRet = FALSE;<br />
<br />
if (::OpenClipboard(m_hWnd))<br />
{<br />
::EmptyClipboard();<br />
::SetClipboardData(CF_BITMAP, bm.m_hObject);<br />
::CloseClipboard();<br />
bRet = TRUE;<br />
}<br />
<br />
memDC.SelectObject(oldbm);<br />
bm.Detach();
::ReleaseDC(m_hWnd, hdc);<br />
<br />
return bRet;<br />
}<br />
<br />
BOOL CXSudokuWnd::PrintBitmap()<br />
{<br />
CPrintDialog printDlg(FALSE,<br />
PD_ALLPAGES | PD_NOPAGENUMS | PD_NOSELECTION | PD_HIDEPRINTTOFILE);<br />
<br />
if (printDlg.DoModal() == IDCANCEL)<br />
return FALSE;<br />
<br />
Invalidate(FALSE);<br />
<br />
CDC dcPrint;<br />
<br />
if (!dcPrint.Attach(printDlg.GetPrinterDC()))<br />
{<br />
AfxMessageBox(_T("No printer found!"));<br />
return FALSE;<br />
}<br />
<br />
dcPrint.m_bPrinting = TRUE;<br />
<br />
DOCINFO di;<br />
::ZeroMemory (&di, sizeof (DOCINFO));<br />
di.cbSize = sizeof (DOCINFO);<br />
di.lpszDocName = _T("XSudoku");<br />
<br />
BOOL bPrintingOK = dcPrint.StartDoc(&di);
<br />
CRect rectClient;<br />
GetWindowRect(rectClient);<br />
ScreenToClient(&rectClient);<br />
CClientDC dcClient(this);<br />
<br />
dcPrint.SetMapMode(MM_ANISOTROPIC);<br />
<br />
CSize sz(dcClient.GetDeviceCaps(LOGPIXELSX), dcClient.GetDeviceCaps(LOGPIXELSY));<br />
dcPrint.SetWindowExt(sz);<br />
int nMargin = sz.cx;<br />
sz = CSize(dcPrint.GetDeviceCaps(LOGPIXELSX), dcPrint.GetDeviceCaps(LOGPIXELSY));<br />
dcPrint.SetViewportExt(sz);<br />
<br />
CPrintInfo Info;<br />
Info.SetMaxPage(1);
int maxw = dcPrint.GetDeviceCaps(HORZRES);<br />
int maxh = dcPrint.GetDeviceCaps(VERTRES);<br />
Info.m_rectDraw.SetRect(0, 0, maxw, maxh);<br />
UINT page = 1;
<br />
dcPrint.StartPage();
Info.m_nCurPage = page;<br />
<br />
GHandle dib;<br />
dib.Attach(GDIUtil::GrabDIB(&dcClient, rectClient));<br />
if (dib.GetHandle() == NULL)<br />
return FALSE;<br />
<br />
GLock lock(dib);<br />
BITMAPINFOHEADER *pBMI = (BITMAPINFOHEADER*)(LPVOID) lock;<br />
<br />
CRect rectPrint = Info.m_rectDraw;<br />
rectPrint.left += nMargin;<br />
rectPrint.right -= nMargin;<br />
rectPrint.top += nMargin;<br />
<br />
CFont *pOldFont = NULL;<br />
<br />
if (m_fontPrint.GetSafeHandle() == NULL)<br />
{<br />
<br />
LOGFONT lf;<br />
memset(&lf, 0, sizeof(lf));<br />
_tcscpy(lf.lfFaceName, _T("Times New Roman"));<br />
lf.lfCharSet = DEFAULT_CHARSET;<br />
lf.lfPitchAndFamily = FF_ROMAN;<br />
lf.lfWeight = FW_NORMAL;<br />
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;<br />
lf.lfHeight = GetFontHeight(14);<br />
m_fontPrint.CreateFontIndirect(&lf);<br />
pOldFont = dcPrint.SelectObject(&m_fontPrint);<br />
}<br />
<br />
int h = dcPrint.DrawText(m_strFile, &rectPrint, DT_LEFT);<br />
CString strTime = _T("");<br />
CTime t = CTime::GetCurrentTime();<br />
strTime = t.Format(_T("Printed on %A, %B %#d, %Y"));<br />
rectPrint.top += h;<br />
h = dcPrint.DrawText(strTime, &rectPrint, DT_LEFT);<br />
rectPrint.top += h;<br />
<br />
int nColors = 0;<br />
if (pBMI->biBitCount <= 8)<br />
nColors = (1<< pBMI->biBitCount);<br />
<br />
::StretchDIBits(dcPrint.GetSafeHdc(),<br />
rectPrint.left,<br />
rectPrint.top + nMargin,<br />
pBMI->biWidth,<br />
pBMI->biHeight,<br />
0,<br />
0,<br />
pBMI->biWidth,<br />
pBMI->biHeight,<br />
(LPBYTE)pBMI + (pBMI->biSize + nColors * sizeof(RGBQUAD)),<br />
(BITMAPINFO*)pBMI,<br />
DIB_RGB_COLORS,<br />
SRCCOPY);<br />
<br />
dcPrint.SelectObject(pOldFont);<br />
<br />
bPrintingOK = (dcPrint.EndPage() > 0);
<br />
if (bPrintingOK)<br />
dcPrint.EndDoc();
else<br />
dcPrint.AbortDoc();
<br />
return TRUE;<br />
}<br />
<br />
CString CXSudokuWnd::ActionCodeToString(BYTE action_code)<br />
{<br />
CString str = _T("");<br />
<br />
#ifdef _DEBUG<br />
switch (action_code)<br />
{<br />
case 0:
break;<br />
case ACTION_CODE_USER_ENTRY:<br />
str = _T("ACTION_CODE_USER_ENTRY");<br />
break;<br />
case ACTION_CODE_USER_ENTRY_REMOVE_ALL:<br />
str = _T("ACTION_CODE_USER_ENTRY_REMOVE_ALL");<br />
break;<br />
case ACTION_CODE_HINT:<br />
str = _T("ACTION_CODE_HINT");<br />
break;<br />
case ACTION_CODE_HINT_REMOVE_ALL:<br />
str = _T("ACTION_CODE_HINT_REMOVE_ALL");<br />
break;<br />
default:<br />
str = _T("ERROR - unknown action code");<br />
break;<br />
}<br />
#else<br />
UNUSED_ALWAYS(action_code);<br />
#endif<br />
<br />
return str;<br />
}<br />
<br />
BOOL CXSudokuWnd::AddUndoAction(int row,<br />
int col,<br />
int action_code,<br />
int action_value)<br />
{<br />
BOOL ok = FALSE;<br />
<br />
if (!m_bEnableUndo)<br />
return ok;<br />
<br />
ASSERT((action_code >= 1) && (action_code <= 4));<br />
<br />
UNDO_BLOCK * pUB = (UNDO_BLOCK *) m_Undo[m_nUndoIndex];<br />
ASSERT(pUB);<br />
<br />
if (pUB)<br />
{<br />
pUB->action_code = (BYTE)action_code;<br />
pUB->action_value = (BYTE)action_value;<br />
pUB->row = (BYTE)row;<br />
pUB->col = (BYTE)col;<br />
int i, j;<br />
for (i = 0; i < 9; i++)<br />
{<br />
for (j = 0; j < 9; j++)<br />
{<br />
pUB->hints[i][j] = (BYTE)m_nHints[i][j];<br />
pUB->user_entries[i][j] = (BYTE)m_nUserEntries[i][j];<br />
}<br />
}<br />
<br />
m_nUndoIndex++;<br />
<br />
m_nUndoLastEntry = m_nUndoIndex;<br />
<br />
if (m_nUndoIndex >= m_nUndoSize)<br />
{<br />
int nOldUndoSize = m_nUndoSize;<br />
m_nUndoSize += UNDO_ARRAY_GROW_BY_SIZE;<br />
BOOL bSetSizeFailed = FALSE;<br />
TRY<br />
{<br />
m_Undo.SetSize(m_nUndoSize);<br />
}<br />
CATCH (CMemoryException, e)<br />
{<br />
bSetSizeFailed = TRUE;<br />
}<br />
END_CATCH<br />
<br />
if (bSetSizeFailed)<br />
{<br />
m_nUndoSize = nOldUndoSize;<br />
m_bEnableUndo = FALSE;<br />
TRACE(_T("ERROR - SetSize failed\n"));<br />
ASSERT(FALSE);<br />
}<br />
else<br />
{<br />
for (j = nOldUndoSize; j < m_nUndoSize; j++)<br />
{<br />
UNDO_BLOCK * pUB = new UNDO_BLOCK;<br />
ASSERT(pUB);<br />
m_Undo[j] = pUB;<br />
}<br />
ok = TRUE;<br />
}<br />
}<br />
else<br />
{<br />
ok = TRUE;<br />
}<br />
}<br />
<br />
return ok;<br />
}<br />
<br />
void CXSudokuWnd::ShowPopup(CPoint point)<br />
{<br />
m_pointPopup = point;<br />
<br />
int row, col, i;<br />
CString str = _T("");<br />
<br />
if (m_bHaveGivens && CellFromPoint(point, row, col))<br />
{<br />
CMenu popup;<br />
VERIFY(popup.CreatePopupMenu());<br />
<br />
UINT nFlags = MF_STRING;<br />
<br />
if (m_bEnableUndo)<br />
{<br />
if (m_nUndoIndex == 0)<br />
nFlags |= MF_DISABLED | MF_GRAYED;<br />
VERIFY(popup.AppendMenu(nFlags, ID_POPUP_UNDO, _T("Undo\tCtrl+Z")));<br />
<br />
nFlags = MF_STRING;<br />
<br />
if (m_nUndoIndex >= m_nUndoLastEntry)<br />
nFlags |= MF_DISABLED | MF_GRAYED;<br />
VERIFY(popup.AppendMenu(nFlags, ID_POPUP_REDO, _T("Redo\tCtrl+Y")));<br />
<br />
VERIFY(popup.AppendMenu(MF_SEPARATOR));<br />
}<br />
<br />
if ((m_nGivens[row][col] == 0) &&<br />
(m_nHints[row][col] == 0) &&<br />
(m_nUserEntries[row][col] == 0) &&<br />
!m_bShowSolution)<br />
{<br />
WORD wCandidates = GetCandidates(row, col);<br />
<br />
if (wCandidates)<br />
{<br />
for (i = 0; i < 9; i++)<br />
{<br />
if (TestBit(wCandidates, i+1))<br />
{<br />
str.Format(_T("Set to %d\t%d"), i+1, i+1);<br />
<br />
VERIFY(popup.AppendMenu(MF_STRING, ID_POPUP_SET_1+i, str));<br />
}<br />
}<br />
VERIFY(popup.AppendMenu(MF_SEPARATOR));<br />
}<br />
<br />
<br />
WORD wUnPencilCandidates = GetUnPenciledCandidates(row, col) & wCandidates;
WORD wPencilCandidates = ~GetUnPenciledCandidates(row, col) & 0x3FE;
<br />
<br />
for (i = 0; i < 9; i++)<br />
{<br />
if (TestBit(wUnPencilCandidates, i+1))<br />
{<br />
str.Format(_T("Rub Out %d"), i+1);<br />
<br />
VERIFY(popup.AppendMenu(MF_STRING, ID_POPUP_UNPENCIL_1+i, str));<br />
}<br />
else<br />
{<br />
if ((TestBit(wPencilCandidates, i+1)) & (TestBit(wCandidates, i+1)))<br />
{<br />
str.Format(_T("Pencil In %d"), i+1);<br />
<br />
VERIFY(popup.AppendMenu(MF_STRING, ID_POPUP_PENCIL_1+i, str));<br />
}<br />
}<br />
}<br />
<br />
VERIFY(popup.AppendMenu(MF_SEPARATOR));<br />
<br />
<br />
}<br />
<br />
nFlags = MF_STRING;<br />
if (m_nGivens[row][col])<br />
nFlags |= MF_DISABLED | MF_GRAYED;<br />
if (m_nHints[row][col])<br />
nFlags |= MF_CHECKED;<br />
else<br />
nFlags |= MF_UNCHECKED;<br />
<br />
VERIFY(popup.AppendMenu(nFlags, ID_POPUP_SHOW_HINT, _T("Show Hint\tF2")));<br />
VERIFY(popup.AppendMenu(MF_STRING, ID_POPUP_REMOVE_ALL_HINTS, _T("Remove All Hints")));<br />
VERIFY(popup.AppendMenu(MF_SEPARATOR));<br />
<br />
nFlags = MF_STRING;<br />
if (m_nUserEntries[row][col] == 0)<br />
nFlags |= MF_DISABLED | MF_GRAYED;<br />
VERIFY(popup.AppendMenu(nFlags, ID_POPUP_REMOVE_USER_ENTRY, _T("Remove User Entry\t0")));<br />
VERIFY(popup.AppendMenu(MF_STRING, ID_POPUP_REMOVE_ALL_USER_ENTRIES, _T("Remove All User Entries")));<br />
VERIFY(popup.AppendMenu(MF_STRING, ID_POPUP_CHECK_USER_ENTRIES, _T("Check User Entries")));<br />
VERIFY(popup.AppendMenu(MF_SEPARATOR));<br />
<br />
nFlags = MF_STRING;<br />
if (m_bShowSolution)<br />
nFlags |= MF_CHECKED;<br />
else<br />
nFlags |= MF_UNCHECKED;<br />
VERIFY(popup.AppendMenu(nFlags, ID_POPUP_SHOW_SOLUTION, _T("Show Solution\tF3")));<br />
<br />
nFlags = MF_STRING;<br />
if (m_bPencilMarks)<br />
nFlags |= MF_CHECKED;<br />
else<br />
nFlags |= MF_UNCHECKED;<br />
VERIFY(popup.AppendMenu(nFlags, ID_POPUP_SHOW_PENCIL_MARKS, _T("Show Pencil Marks\tF4")));<br />
<br />
VERIFY(popup.AppendMenu(MF_STRING, ID_POPUP_RESET, _T("Reset")));<br />
VERIFY(popup.AppendMenu(MF_SEPARATOR));<br />
<br />
VERIFY(popup.AppendMenu(MF_STRING, ID_POPUP_PRINT, _T("Print Window...\tCtrl+P")));<br />
VERIFY(popup.AppendMenu(MF_STRING, ID_POPUP_COPY, _T("Copy Window to Clipboard")));<br />
VERIFY(popup.AppendMenu(MF_SEPARATOR));<br />
<br />
for (i = 0; i < 9; i++)<br />
{<br />
nFlags = MF_STRING;<br />
if (m_nHighlightNumber == (i+1))<br />
nFlags |= MF_CHECKED;<br />
else<br />
nFlags |= MF_UNCHECKED;<br />
<br />
str.Format(_T("Highlight %d\tCtrl+%d"), i+1, i+1);<br />
<br />
VERIFY(popup.AppendMenu(nFlags, ID_POPUP_HIGHLIGHT_1+i, str));<br />
}<br />
<br />
VERIFY(popup.AppendMenu(MF_SEPARATOR));<br />
VERIFY(popup.AppendMenu(MF_STRING, ID_APP_ABOUT, _T("About XSudokuWndDll...\tCtrl+F1")));<br />
<br />
<br />
CPoint pt = point;<br />
ClientToScreen(&pt);<br />
VERIFY(popup.TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON, pt.x+1, pt.y+1, this));<br />
}<br />
}<br />
<br />
<br />
void CXSudokuWnd::OnRemoveUserEntry()<br />
{<br />
int row, col;<br />
<br />
if (CellFromPoint(m_pointPopup, row, col))<br />
{<br />
AddUndoAction(row, col, ACTION_CODE_USER_ENTRY, 0);<br />
m_nUserEntries[row][col] = 0;<br />
Invalidate(FALSE);<br />
}<br />
}<br />
<br />
void CXSudokuWnd::OnRemoveAllUserEntries()<br />
{<br />
AddUndoAction(m_nCurRow, m_nCurCol, ACTION_CODE_USER_ENTRY_REMOVE_ALL, 0);<br />
<br />
for (int i = 0; i < 9; i++)<br />
{<br />
for (int j = 0; j < 9; j++)<br />
{<br />
m_nUserEntries[i][j] = 0;<br />
}<br />
}<br />
Invalidate(FALSE);<br />
}<br />
<br />
void CXSudokuWnd::OnCheckUserEntries()<br />
{<br />
SWITCH_RESOURCE;
<br />
CString str = _T("");<br />
CString strColumns = _T("");<br />
VERIFY(strColumns.LoadString(IDS_COLUMN_LABELS));<br />
<br />
CString strFormat = _T("");<br />
VERIFY(strFormat.LoadString(IDS_USER_ENTRY));<br />
CString strIncorrect = _T("");<br />
VERIFY(strIncorrect.LoadString(IDS_INCORRECT));<br />
strFormat += strIncorrect;<br />
strFormat += _T(".\r\n");<br />
<br />
CString strMessage = _T("");<br />
int nUserEntries = 0;<br />
<br />
for (int i = 0; i < 9; i++)<br />
{<br />
for (int j = 0; j < 9; j++)<br />
{<br />
if (m_nUserEntries[i][j] != 0)<br />
{<br />
nUserEntries++;<br />
if (m_nUserEntries[i][j] != m_nSolution[i][j])<br />
{<br />
strMessage.Format(strFormat, m_nUserEntries[i][j], i+1, strColumns[j]);<br />
str += strMessage;<br />
}<br />
}<br />
}<br />
}<br />
<br />
if (str.IsEmpty())<br />
{<br />
if (nUserEntries == 0)<br />
AfxMessageBox(IDS_NO_USER_ENTRY);<br />
else<br />
AfxMessageBox(IDS_USER_ENTRY_OK, MB_ICONINFORMATION);<br />
}<br />
else<br />
{<br />
AfxMessageBox(str);<br />
}<br />
}<br />
<br />
void CXSudokuWnd::OnShowHint()<br />
{<br />
if ((m_nCurRow != -1) && (m_nCurCol != -1))<br />
{<br />
if (m_bHaveGivens)<br />
{<br />
int nHint = (m_nHints[m_nCurRow][m_nCurCol] == 0) ?<br />
m_nSolution[m_nCurRow][m_nCurCol] : 0;<br />
<br />
AddUndoAction(m_nCurRow, m_nCurCol, ACTION_CODE_HINT, nHint);<br />
<br />
m_nHints[m_nCurRow][m_nCurCol] = nHint;<br />
<br />
Invalidate(FALSE);<br />
}<br />
}<br />
}<br />
<br />
void CXSudokuWnd::OnPopupShowHint()<br />
{<br />
int row, col;<br />
<br />
if (m_bHaveGivens && CellFromPoint(m_pointPopup, row, col))<br />
{<br />
int nHint = (m_nHints[row][col] == 0) ?<br />
m_nSolution[row][col] : 0;<br />
<br />
AddUndoAction(row, col, ACTION_CODE_HINT, nHint);<br />
<br />
m_nHints[row][col] = nHint;<br />
<br />
Invalidate(FALSE);<br />
}<br />
}<br />
<br />
void CXSudokuWnd::OnRemoveAllHints()<br />
{<br />
AddUndoAction(m_nCurRow, m_nCurCol, ACTION_CODE_HINT_REMOVE_ALL, 0);<br />
<br />
for (int i = 0; i < 9; i++)<br />
{<br />
for (int j = 0; j < 9; j++)<br />
{<br />
m_nHints[i][j] = 0;<br />
}<br />
}<br />
Invalidate(FALSE);<br />
}<br />
<br />
void CXSudokuWnd::OnReset()<br />
{<br />
SWITCH_RESOURCE;
<br />
int rc = AfxMessageBox(IDS_RESET, MB_YESNO|MB_ICONQUESTION);<br />
<br />
if (rc == IDYES)<br />
{<br />
Reset(FALSE);<br />
Invalidate(FALSE);<br />
}<br />
}<br />
<br />
void CXSudokuWnd::OnPrintWindow()<br />
{<br />
PrintBitmap();<br />
}<br />
<br />
void CXSudokuWnd::OnCopyWindow()<br />
{<br />
CaptureBitmap();<br />
}<br />
<br />
void CXSudokuWnd::OnShowSolution()<br />
{<br />
m_bShowSolution = !m_bShowSolution;<br />
SetShowSolution(m_bShowSolution);<br />
}<br />
<br />
void CXSudokuWnd::OnShowPencilMarks()<br />
{<br />
m_bPencilMarks = !m_bPencilMarks;<br />
SetShowPencilMarks(m_bPencilMarks);<br />
}<br />
<br />
void CXSudokuWnd::OnPopupSet(UINT nID)<br />
{<br />
SWITCH_RESOURCE;
<br />
int nValue = nID - ID_POPUP_SET_1 + 1;<br />
<br />
int row, col;<br />
<br />
if (CellFromPoint(m_pointPopup, row, col))<br />
{<br />
AddUndoAction(row, col, ACTION_CODE_USER_ENTRY, nValue);<br />
<br />
m_nUserEntries[row][col] = nValue;<br />
<br />
CString str = _T("");<br />
CString strColumns = _T("");<br />
VERIFY(strColumns.LoadString(IDS_COLUMN_LABELS));<br />
str.Format(IDS_USER_ENTRY, nValue, row+1, strColumns[col]);<br />
int nType = 0;<br />
<br />
CString strCorrect = _T("");<br />
if (nValue == m_nSolution[row][col])<br />
{<br />
VERIFY(strCorrect.LoadString(IDS_CORRECT));<br />
}<br />
else<br />
{<br />
VERIFY(strCorrect.LoadString(IDS_INCORRECT));<br />
nType = 1;<br />
}<br />
str += strCorrect;<br />
<br />
if (m_hWndMessage && ::IsWindow(m_hWndMessage))<br />
::SendMessage(m_hWndMessage, WM_XSUDOKU, nType,<br />
(LPARAM)(LPCTSTR)str);<br />
<br />
Invalidate(FALSE);<br />
}<br />
}<br />
<br />
void CXSudokuWnd::OnPopupUnPencil(UINT nID)
{<br />
SWITCH_RESOURCE;
<br />
int nValue = nID - ID_POPUP_UNPENCIL_1 + 1;<br />
<br />
int row, col;<br />
<br />
if (CellFromPoint(m_pointPopup, row, col))<br />
{<br />
AddUndoAction(row, col, ACTION_CODE_USER_ENTRY, nValue);<br />
SetBit(m_nUnPencil[row][col],nValue);<br />
Invalidate(FALSE);<br />
}<br />
}<br />
<br />
void CXSudokuWnd::OnPopupPencil(UINT nID)
{<br />
SWITCH_RESOURCE;
<br />
int nValue = nID - ID_POPUP_PENCIL_1 + 1;<br />
<br />
int row, col;<br />
<br />
if (CellFromPoint(m_pointPopup, row, col))<br />
{<br />
AddUndoAction(row, col, ACTION_CODE_USER_ENTRY, nValue);<br />
int nBit = 0;<br />
SetBit(nBit,nValue);<br />
m_nUnPencil[row][col]&=~nBit;<br />
Invalidate(FALSE);<br />
}<br />
}<br />
<br />
void CXSudokuWnd::OnPopupHighlight(UINT nID)<br />
{<br />
int nHighlightNumber = nID - ID_POPUP_HIGHLIGHT_1 + 1;<br />
<br />
if (m_nHighlightNumber == nHighlightNumber)<br />
m_nHighlightNumber = 0;<br />
else<br />
m_nHighlightNumber = nHighlightNumber;<br />
<br />
Invalidate(FALSE);<br />
}<br />
<br />
void CXSudokuWnd::OnHighlight(UINT nID)<br />
{<br />
int nHighlightNumber = nID - ID_HIGHLIGHT_0;<br />
<br />
if (nHighlightNumber == 0)<br />
m_nHighlightNumber = 0;<br />
else if (m_nHighlightNumber == nHighlightNumber)<br />
m_nHighlightNumber = 0;<br />
else<br />
m_nHighlightNumber = nHighlightNumber;<br />
<br />
Invalidate(FALSE);<br />
}<br />
<br />
void CXSudokuWnd::OnRightClick()<br />
{<br />
CRect rectCell = GetCellRect(m_nCurRow, m_nCurCol);<br />
CPoint point;<br />
point.x = rectCell.left + rectCell.Width()/2;<br />
point.y = rectCell.top + rectCell.Height()/2;<br />
ShowPopup(point);<br />
}<br />
<br />
void CXSudokuWnd::OnColorPrefs()<br />
{<br />
ShowColorPrefsDlg();<br />
}<br />
<br />
void CXSudokuWnd::OnLoadSample()<br />
{<br />
#ifdef _DEBUG<br />
CString strSudoku = _T("708000300000201000500000000040000026300080000000100090090600004000070500000000000");<br />
LoadFromString(strSudoku, strSudoku.GetLength());<br />
Invalidate(FALSE);<br />
#endif<br />
}<br />
<br />
void CXSudokuWnd::OnEditUndo()<br />
{<br />
TRACE(_T("in CXSudokuWnd::OnEditUndo\n"));<br />
<br />
if (!m_bEnableUndo)<br />
return;<br />
<br />
if (m_nUndoIndex > 0)<br />
{<br />
int index = m_nUndoIndex - 1;<br />
UNDO_BLOCK * pUB = (UNDO_BLOCK *) m_Undo[index];<br />
ASSERT(pUB);<br />
if (pUB)<br />
{<br />
m_nCurRow = (int) pUB->row;<br />
m_nCurCol = (int) pUB->col;<br />
int i, j;<br />
for (i = 0; i < 9; i++)<br />
{<br />
for (j = 0; j < 9; j++)<br />
{<br />
m_nHints[i][j] = (int) pUB->hints[i][j];<br />
m_nUserEntries[i][j] = (int) pUB->user_entries[i][j];<br />
}<br />
}<br />
<br />
#ifdef _DEBUG<br />
CString str = ActionCodeToString(pUB->action_code);<br />
if (!str.IsEmpty())<br />
{<br />
TRACE(_T("undoing action '%s'\n"), str);<br />
}<br />
#endif<br />
<br />
m_nUndoIndex--;<br />
m_bShowSolution = FALSE;<br />
Invalidate(FALSE);<br />
}<br />
}<br />
}<br />
<br />
void CXSudokuWnd::OnEditRedo()<br />
{<br />
TRACE(_T("in CXSudokuWnd::OnEditRedo\n"));<br />
<br />
if (!m_bEnableUndo)<br />
return;<br />
<br />
if (m_nUndoIndex < m_nUndoLastEntry)<br />
{<br />
int index = m_nUndoIndex;<br />
UNDO_BLOCK * pUB = (UNDO_BLOCK *) m_Undo[index];<br />
ASSERT(pUB);<br />
if (pUB)<br />
{<br />
m_nCurRow = (int) pUB->row;<br />
m_nCurCol = (int) pUB->col;<br />
int i, j;<br />
<br />
switch (pUB->action_code)<br />
{<br />
case 0:
break;<br />
<br />
case ACTION_CODE_USER_ENTRY:<br />
m_nUserEntries[m_nCurRow][m_nCurCol] = pUB->action_value;<br />
break;<br />
<br />
case ACTION_CODE_USER_ENTRY_REMOVE_ALL:<br />
for (i = 0; i < 9; i++)<br />
{<br />
for (j = 0; j < 9; j++)<br />
{<br />
m_nUserEntries[i][j] = 0;<br />
}<br />
}<br />
break;<br />
<br />
case ACTION_CODE_HINT:<br />
m_nHints[m_nCurRow][m_nCurCol] = pUB->action_value;<br />
break;<br />
<br />
case ACTION_CODE_HINT_REMOVE_ALL:<br />
for (i = 0; i < 9; i++)<br />
{<br />
for (j = 0; j < 9; j++)<br />
{<br />
m_nHints[i][j] = 0;<br />
}<br />
}<br />
break;<br />
<br />
default:<br />
break;<br />
}<br />
<br />
#ifdef _DEBUG<br />
CString str = ActionCodeToString(pUB->action_code);<br />
if (!str.IsEmpty())<br />
{<br />
TRACE(_T("redoing undo action '%s'\n"), str);<br />
}<br />
#endif<br />
<br />
m_nUndoIndex++;<br />
m_bShowSolution = FALSE;<br />
Invalidate(FALSE);<br />
}<br />
}<br />
}<br />
<br />
void CXSudokuWnd::OnAppAbout()<br />
{<br />
SWITCH_RESOURCE;
CAboutDlg dlg;<br />
dlg.DoModal();<br />
}<br />
|