// SudokuEdit.cpp : implementation file
// Adapted from CodeProject work by PJ Arends
#include "stdafx.h"
#include "SudokuEdit.h"
#include "SudokuPuzzle.h"
#include <vector>
#include <sstream>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define MES_UNDO _T("&Show &History")
#define MES_COPY _T("Show &Answer")
#define MES_CUT _T("&Cut")
#define MES_PASTE _T("&Paste")
#define MES_DELETE _T("&Delete")
#define MES_SELECTALL _T("Select &All")
#define ME_SELECTALL WM_USER + 0x7000
BEGIN_MESSAGE_MAP(CSudokuEdit, CEdit)
ON_WM_CONTEXTMENU()
ON_WM_CTLCOLOR_REFLECT()
END_MESSAGE_MAP()
CSudokuEdit::CSudokuEdit() :
m_pPuzzle(NULL)
, cbAnswer(NULL)
, cbHint(NULL)
, cbBlank(NULL)
, cbImposs(NULL)
, cfNormal(NULL)
, cfAnswer(NULL)
, cfPossibilities(NULL)
, cfImposs(NULL)
, crNormalText(RGB(0,0,0))
, crAnswerText(RGB(0,0,0))
, crHintText(RGB(0,0,0))
, crImpossText(RGB(0,0,0))
, m_pLB(NULL)
, bChanged(false)
, m_guess(0)
, m_iCellNum(0)
, state(CS_UNINITIALIZED)
, prevState(CS_UNINITIALIZED)
{
state = CS_UNINITIALIZED;
}
void CSudokuEdit::OnContextMenu(CWnd* pWnd, CPoint point)
{
SetFocus();
CMenu menu;
menu.CreatePopupMenu();
BOOL bReadOnly = GetStyle() & ES_READONLY;
DWORD flags = CanUndo() && !bReadOnly ? 0 : MF_GRAYED;
menu.InsertMenu(0, MF_BYPOSITION, EM_UNDO,
MES_UNDO);
menu.InsertMenu(1, MF_BYPOSITION | MF_SEPARATOR);
int answer = m_pPuzzle->GetAnswer(m_iCellNum);
if (answer == 0)
flags = MF_GRAYED;
else
flags = 0;
menu.InsertMenu(2, MF_BYPOSITION | flags, WM_COPY,
MES_COPY);
//flags = (flags == MF_GRAYED || bReadOnly) ? MF_GRAYED : 0;
//menu.InsertMenu(2, MF_BYPOSITION | flags, WM_CUT,
// MES_CUT);
//menu.InsertMenu(4, MF_BYPOSITION | flags, WM_CLEAR,
// MES_DELETE);
//flags = IsClipboardFormatAvailable(CF_TEXT) &&
// !bReadOnly ? 0 : MF_GRAYED;
//menu.InsertMenu(4, MF_BYPOSITION | flags, WM_PASTE,
// MES_PASTE);
//menu.InsertMenu(6, MF_BYPOSITION | MF_SEPARATOR);
//int len = GetWindowTextLength();
//flags = (!len || (LOWORD(sel) == 0 && HIWORD(sel) ==
// len)) ? MF_GRAYED : 0;
//menu.InsertMenu(7, MF_BYPOSITION | flags, ME_SELECTALL,
// MES_SELECTALL);
menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON |
TPM_RIGHTBUTTON, point.x, point.y, this);
}
BOOL CSudokuEdit::OnCommand(WPARAM wParam, LPARAM lParam)
{
switch (LOWORD(wParam))
{
case EM_UNDO: // hijacked - show history
ShowReasons();
break;
case WM_COPY: // hijacked - show answer
ShowAnswer();
break;
case WM_CUT:
case WM_CLEAR:
case WM_PASTE:
return (BOOL)SendMessage(LOWORD(wParam));
case ME_SELECTALL:
return (BOOL)SendMessage (EM_SETSEL, 0, -1);
default:
return CEdit::OnCommand(wParam, lParam);
}
return TRUE;
}
HBRUSH CSudokuEdit::CtlColor(CDC* pDC, UINT nCtlColor)
{
HBRUSH hbr;
if (state == CS_UNINITIALIZED)
{
return NULL;
}
// Set the background mode for text to transparent
// so background will show thru.
pDC->SetBkMode(TRANSPARENT);
switch (state)
{
case CS_NORMAL:
case CS_GUESS:
hbr = *cbBlank;
pDC->SetTextColor(crNormalText);
pDC->SetBkColor(crNormalText);
break;
case CS_HINT:
hbr = *cbHint;
pDC->SetTextColor(crHintText);
pDC->SetBkColor(crHintText);
break;
case CS_ANSWER:
hbr = *cbAnswer;
pDC->SetTextColor(crAnswerText);
pDC->SetBkColor(crAnswerText);
break;
case CS_IMPOSSIBLE:
hbr = *cbImposs;
pDC->SetTextColor(crImpossText);
pDC->SetBkColor(crImpossText);
break;
}
// Changed text will always be read
if (bChanged)
{
pDC->SetTextColor(RGB(255,0,0));
pDC->SetBkColor(RGB(255,0,0));
hbr = *cbChanged;
}
return hbr;
}
void CSudokuEdit::SetCellBrushes(CBrush* pbNorm, CBrush* pbAnswer, CBrush* pbPoss, CBrush* pbImposs)
{
cbBlank = pbNorm;
cbAnswer = pbAnswer;
cbHint = pbPoss;
cbImposs = pbImposs;
cbChanged = new CBrush(RGB(225, 239, 143));
}
void CSudokuEdit::SetCellFonts(CFont* norm, CFont* answer, CFont* poss, CFont* imposs)
{
cfNormal = norm;
cfAnswer = answer;
cfPossibilities = poss;
cfImposs = imposs;
};
void CSudokuEdit::SetCellTextColors(COLORREF norm, COLORREF answer, COLORREF poss, COLORREF imposs)
{
crNormalText = norm;
crAnswerText = answer;
crHintText = poss;
crImpossText = imposs;
}
void CSudokuEdit::RefreshCell(bool hintsOn, bool showAnswers)
{
std::string sPoss;
char currText[16];
std::stringstream ss;
int answer = m_pPuzzle->GetPossibilitiesString(m_iCellNum, sPoss);
if (showAnswers && (answer != 0))
{
state = CS_ANSWER;
ss << answer;
SetReadOnly(TRUE);
SetFont(cfAnswer);
SetWindowText(ss.str().c_str());
return;
}
if (hintsOn && (state != CS_HINT) && (state != CS_ANSWER))
{
prevState = state;
state = CS_HINT;
}
else if (!hintsOn && (state == CS_HINT))
{
state = prevState;
}
GetWindowText(currText, 16);
int guess = atoi(currText);
SetReadOnly(FALSE);
switch (state)
{
case CS_ANSWER:
ss << answer;
SetReadOnly(TRUE);
SetFont(cfAnswer);
SetWindowText(ss.str().c_str());
break;
case CS_GUESS:
ss << m_guess;
SetReadOnly(FALSE);
SetFont(cfNormal);
SetWindowText(ss.str().c_str());
break;
case CS_HINT:
SetReadOnly(TRUE);
SetFont(cfPossibilities);
SetWindowText(sPoss.c_str());
break;
case CS_NORMAL:
SetFont(cfNormal);
SetWindowText(ss.str().c_str());
break;
case CS_IMPOSSIBLE:
SetFont(cfImposs);
break;
default:
break;
}
return;
if (state == CS_ANSWER)
{
std::stringstream ss;
ss << answer;
}
else if ((guess == 0) && (answer != 0))
{
std::stringstream ss;
ss << answer;
state = CS_ANSWER;
//SetReadOnly(TRUE);
SetFont(cfNormal);
SetWindowText(ss.str().c_str());
}
else
{
if (hintsOn)
{
m_guess = guess;
state = CS_HINT;
SetReadOnly(TRUE);
SetFont(cfPossibilities);
SetWindowText(sPoss.c_str());
}
else
{
SetReadOnly(FALSE);
if (state == CS_IMPOSSIBLE)
{
SetFont(cfImposs);
}
else
{
state = CS_NORMAL;
SetFont(cfNormal);
if (m_guess == 0)
SetWindowText("");
else
{
std::stringstream ss;
ss << m_guess;
SetWindowText(ss.str().c_str());
}
}
}
}
}
void CSudokuEdit::ShowReasons()
{
if (m_pLB)
{
m_pLB->ResetContent();
std::vector<std::string> sReasons;
std::vector<std::string>::iterator reasonsIter;
m_pPuzzle->GetReasons(m_iCellNum, sReasons);
for (reasonsIter = sReasons.begin(); reasonsIter != sReasons.end(); ++reasonsIter)
{
m_pLB->AddString(reasonsIter->c_str());
}
}
}
void CSudokuEdit::ShowAnswer()
{
int answer = m_pPuzzle->GetAnswer(m_iCellNum);
if (answer != 0)
{
std::stringstream ss;
ss << answer;
state = CS_ANSWER;
//SetReadOnly(TRUE);
SetFont(cfAnswer);
SetWindowText(ss.str().c_str());
}
}