374 lines
8.9 KiB
C++
374 lines
8.9 KiB
C++
// calcdlg.cpp : implementation file
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "utsampleabout.h"
|
|
#include "calc.h"
|
|
#include "calcdlg.h"
|
|
#include "calckey.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CCalculator dialog
|
|
|
|
CCalculator::CCalculator(CWnd* pParent /*=NULL*/)
|
|
: CDialog(CCalculator::IDD, pParent)
|
|
{
|
|
//{{AFX_DATA_INIT(CCalculator)
|
|
// NOTE: the ClassWizard will add member initialization here
|
|
//}}AFX_DATA_INIT
|
|
|
|
// Note that LoadAccelerator does not require DestroyAcceleratorTable
|
|
m_hAccel = LoadAccelerators(AfxGetResourceHandle(),MAKEINTRESOURCE(IDD));
|
|
|
|
// Initialize the move variable
|
|
m_bTrackMove = FALSE;
|
|
}
|
|
|
|
void CCalculator::DoDataExchange(CDataExchange* pDX)
|
|
{
|
|
CDialog::DoDataExchange(pDX);
|
|
//{{AFX_DATA_MAP(CCalculator)
|
|
// NOTE: the ClassWizard will add DDX and DDV calls here
|
|
//}}AFX_DATA_MAP
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CCalculator Internal Methods
|
|
|
|
// Called to perform an operation - add, subtract, etc.
|
|
void CCalculator::PerformOperation()
|
|
{
|
|
// Return if in an invalid state
|
|
if (m_errorState != ErrNone)
|
|
return;
|
|
|
|
// If we can perform an operation...
|
|
if (m_bOperandAvail)
|
|
{
|
|
// Perform the selected operation
|
|
if (m_operator == OpNone)
|
|
m_accum = m_operand;
|
|
else if (m_operator == OpMultiply)
|
|
m_accum *= m_operand;
|
|
else if (m_operator == OpDivide)
|
|
{
|
|
if (m_operand == 0)
|
|
m_errorState = ErrDivideByZero;
|
|
else
|
|
m_accum /= m_operand;
|
|
}
|
|
else if (m_operator == OpAdd)
|
|
m_accum += m_operand;
|
|
else if (m_operator == OpSubtract)
|
|
m_accum -= m_operand;
|
|
}
|
|
|
|
// Set the next state
|
|
m_bOperandAvail = FALSE;
|
|
UpdateDisplay();
|
|
}
|
|
|
|
// Called to update the total display
|
|
void CCalculator::UpdateDisplay()
|
|
{
|
|
// Display "Error" is an error occurs, otherwise display the total
|
|
CString str;
|
|
if (m_errorState != ErrNone)
|
|
str = "Error";
|
|
else
|
|
{
|
|
long lVal = (m_bOperandAvail) ? m_operand : m_accum;
|
|
str.Format(_T("%ld"), lVal);
|
|
}
|
|
|
|
GetDlgItem(IDC_DISPLAY)->SetWindowText(str);
|
|
}
|
|
|
|
// Draws a tracking rectangle by inverting an area the size of the dialog
|
|
void CCalculator::InvertTracker(CPoint point)
|
|
{
|
|
CRect rectFrame;
|
|
GetWindowRect(&rectFrame);
|
|
CDC dc;
|
|
dc.Attach(::GetDC(NULL));
|
|
|
|
// Create the frame with a reverse video effect
|
|
dc.PatBlt(point.x-m_ptMouse.x, point.y-m_ptMouse.y, rectFrame.Width(),
|
|
2, PATINVERT);
|
|
dc.PatBlt(point.x-m_ptMouse.x+rectFrame.Width(), point.y-m_ptMouse.y,
|
|
2, rectFrame.Height(), PATINVERT);
|
|
dc.PatBlt(point.x-m_ptMouse.x, point.y-m_ptMouse.y+rectFrame.Height(),
|
|
rectFrame.Width()+2, 2, PATINVERT);
|
|
dc.PatBlt(point.x-m_ptMouse.x, point.y-m_ptMouse.y+2, 2,
|
|
rectFrame.Height()-2, PATINVERT);
|
|
::ReleaseDC(NULL,dc.Detach());
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CCalculator, CDialog)
|
|
//{{AFX_MSG_MAP(CCalculator)
|
|
ON_COMMAND_RANGE(IDC_0,IDC_9,OnNumber)
|
|
ON_BN_CLICKED(IDC_ADD, OnAdd)
|
|
ON_BN_CLICKED(IDC_CLEAR, OnClear)
|
|
ON_BN_CLICKED(IDC_DIV, OnDiv)
|
|
ON_BN_CLICKED(IDC_EQUAL, OnEqual)
|
|
ON_BN_CLICKED(IDC_MUL, OnMul)
|
|
ON_BN_CLICKED(IDC_SUB, OnSub)
|
|
ON_BN_CLICKED(IDC_ABOUT, OnAbout)
|
|
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_LBUTTONUP()
|
|
ON_WM_MOUSEMOVE()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CCalculator message handlers
|
|
|
|
BOOL CCalculator::OnInitDialog()
|
|
{
|
|
CDialog::OnInitDialog();
|
|
|
|
CString sCaption;
|
|
sCaption.LoadString(IDR_MAINFRAME);
|
|
SetWindowText(sCaption);
|
|
|
|
// Set the icon for this dialog. The framework does this automatically
|
|
// when the application's main window is not a dialog
|
|
SetIcon(m_hIcon, TRUE); // Set big icon
|
|
SetIcon(m_hIcon, FALSE); // Set small icon
|
|
|
|
// Set the rounded-corner calculator shape
|
|
CPoint point(30,30);
|
|
SetRoundRectShape(NULL,&point);
|
|
|
|
// Make sure the starfield paints before everything else
|
|
GetDlgItem(IDC_STARFIELD)->SetWindowPos(&wndTop,0,0,0,0,
|
|
SWP_NOMOVE|SWP_NOSIZE);
|
|
|
|
// Shape the number keys
|
|
CCalcKey* pKey;
|
|
int nID;
|
|
|
|
for(nID = IDC_0; nID <= IDC_9; nID++)
|
|
{
|
|
pKey = (CCalcKey*) GetDlgItem(nID);
|
|
ASSERT(pKey != NULL);
|
|
|
|
// Make them star shaped
|
|
pKey->SetStarShape();
|
|
|
|
// Set color to yellow when not pressed, red when pressed
|
|
pKey->SetColors(RGB(0,0,0),RGB(255,255,0),RGB(0,0,0),RGB(255,0,0));
|
|
}
|
|
|
|
// Shape the operation keys
|
|
for(nID = IDC_SUB; nID <= IDC_ADD; nID++)
|
|
{
|
|
pKey = (CCalcKey*) GetDlgItem(nID);
|
|
ASSERT(pKey != NULL);
|
|
|
|
// Make them round-corned rectangles
|
|
CPoint point(20,20);
|
|
pKey->SetRoundRectShape(NULL,&point);
|
|
|
|
// Set color to light gray when not pressed, white when pressed
|
|
pKey->SetColors(RGB(0,0,0),RGB(192,192,192),
|
|
RGB(0,0,0),RGB(255,255,255));
|
|
}
|
|
|
|
// Set the total display's appearance
|
|
pKey = (CCalcKey*) GetDlgItem(IDC_DISPLAY);
|
|
ASSERT(pKey != NULL);
|
|
|
|
// Make it a white ellipse
|
|
pKey->SetEllipseShape(NULL);
|
|
pKey->SetColors(RGB(0,0,0),RGB(255,255,255));
|
|
|
|
// Set the close button's appearance
|
|
pKey = (CCalcKey*) GetDlgItem(IDCANCEL);
|
|
ASSERT(pKey != NULL);
|
|
|
|
// Make it a light gray ellipse
|
|
pKey->SetEllipseShape(NULL);
|
|
pKey->SetColors(RGB(0,0,0),RGB(192,192,192));
|
|
|
|
// Set the close button's appearance
|
|
pKey = (CCalcKey*) GetDlgItem(IDC_ABOUT);
|
|
ASSERT(pKey != NULL);
|
|
|
|
// Make it a light gray ellipse
|
|
pKey->SetEllipseShape(NULL);
|
|
// Set color to light gray when not pressed, white when pressed
|
|
pKey->SetColors(RGB(0,0,0),RGB(192,192,192),
|
|
RGB(0,0,0),RGB(255,255,255));
|
|
// Center the dialog on the screen
|
|
CenterWindow();
|
|
|
|
// Initialize the calculator's work variables
|
|
OnClear();
|
|
|
|
return TRUE; // return TRUE unless you set the focus to a control
|
|
}
|
|
|
|
// Called when a number button is clicked
|
|
void CCalculator::ClickedNumber(long l)
|
|
{
|
|
// Return if in an invalid state
|
|
if (m_errorState != ErrNone)
|
|
return;
|
|
|
|
// If we can perform an operation...
|
|
if (!m_bOperandAvail)
|
|
m_operand = 0L;
|
|
|
|
// Set the next state
|
|
SetOperand(m_operand*10+l);
|
|
UpdateDisplay();
|
|
}
|
|
void CCalculator::OnAbout(){
|
|
CUTSampleAboutDlg aboutDlg(IDR_MAINFRAME,ID_DESCRIPTION_FILE);
|
|
aboutDlg.DoModal();
|
|
}
|
|
|
|
// Called when the left mouse button is pressed
|
|
void CCalculator::OnLButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
UNREFERENCED_PARAMETER(nFlags);
|
|
|
|
// Save the starting point where the mouse was clicked
|
|
m_ptMouse = point;
|
|
|
|
// Save the point in screen coordinates too
|
|
ClientToScreen(&point);
|
|
m_ptLast = point;
|
|
}
|
|
|
|
// Called when the left mouse button is released
|
|
void CCalculator::OnLButtonUp(UINT nFlags, CPoint point)
|
|
{
|
|
UNREFERENCED_PARAMETER(nFlags);
|
|
|
|
// If moving...
|
|
if (m_bTrackMove)
|
|
{
|
|
// Reset for next move
|
|
m_bTrackMove = FALSE;
|
|
ReleaseCapture();
|
|
InvertTracker(m_ptLast);
|
|
|
|
// Calculate how far we have moved and update
|
|
ClientToScreen(&point);
|
|
SetWindowPos(NULL, point.x-m_ptMouse.x, point.y-m_ptMouse.y,0,0,
|
|
SWP_NOZORDER|SWP_NOSIZE);
|
|
}
|
|
}
|
|
|
|
// Called when the mouse moves
|
|
void CCalculator::OnMouseMove(UINT nFlags, CPoint point)
|
|
{
|
|
// Are we not moving the window and the left mouse button is now down???
|
|
if(!m_bTrackMove && (nFlags & MK_LBUTTON))
|
|
{
|
|
// Begin the move operation
|
|
m_bTrackMove = TRUE;
|
|
SetCapture();
|
|
InvertTracker(m_ptLast);
|
|
}
|
|
|
|
// If we moving...
|
|
if (m_bTrackMove)
|
|
{
|
|
// Remove the old tracking rectangle
|
|
ClientToScreen(&point);
|
|
InvertTracker(m_ptLast);
|
|
|
|
// Draw a new one
|
|
m_ptLast = point;
|
|
InvertTracker(m_ptLast);
|
|
}
|
|
else CWnd::OnMouseMove(nFlags,point);
|
|
}
|
|
|
|
// Called when a number key is pressed
|
|
void CCalculator::OnNumber(UINT nID)
|
|
{
|
|
ASSERT(nID >= IDC_0 && nID <= IDC_9);
|
|
ClickedNumber(nID-IDC_0);
|
|
}
|
|
|
|
// Called when the clear key is pressed
|
|
void CCalculator::OnClear()
|
|
{
|
|
// Reset the internal state, empty the totals
|
|
m_operator = OpNone;
|
|
m_operand = 0L;
|
|
m_accum = 0L;
|
|
m_bOperandAvail = FALSE;
|
|
m_errorState = ErrNone;
|
|
UpdateDisplay();
|
|
}
|
|
|
|
// Called when the divide key is pressed
|
|
void CCalculator::OnDiv()
|
|
{
|
|
// Perform the division and save the operation
|
|
PerformOperation();
|
|
m_operator = OpDivide;
|
|
}
|
|
|
|
// Called when the equal key is pressed
|
|
void CCalculator::OnEqual()
|
|
{
|
|
// Get the total and save the operation
|
|
PerformOperation();
|
|
m_operator = OpNone;
|
|
}
|
|
|
|
// Called when the subtract key is pressed
|
|
void CCalculator::OnSub()
|
|
{
|
|
// Perform the subtraction and save the operation
|
|
PerformOperation();
|
|
m_operator = OpSubtract;
|
|
}
|
|
|
|
// Called when the add key is pressed
|
|
void CCalculator::OnAdd()
|
|
{
|
|
// Perform the addition and save the operation
|
|
PerformOperation();
|
|
m_operator = OpAdd;
|
|
}
|
|
|
|
// Called when the multiply key is pressed
|
|
void CCalculator::OnMul()
|
|
{
|
|
// Perform the multiplication and save the operation
|
|
PerformOperation();
|
|
m_operator = OpMultiply;
|
|
}
|
|
|
|
// Saves the last operand value
|
|
void CCalculator::SetOperand(long nNewValue)
|
|
{
|
|
// Save the operand value and indicate that operation was performed
|
|
m_operand = nNewValue;
|
|
m_bOperandAvail = TRUE;
|
|
}
|
|
|
|
// Translate the accelerators for the button keys
|
|
BOOL CCalculator::PreTranslateMessage(MSG* pMsg)
|
|
{
|
|
if (m_hAccel != NULL && TranslateAccelerator(m_hWnd, m_hAccel, pMsg))
|
|
return TRUE;
|
|
|
|
return CDialog::PreTranslateMessage(pMsg);
|
|
}
|