// VisualCalcDlg.cpp : implementation file
//
#include "stdafx.h"
#include "VisualCalc.h"
#include "VisualCalcDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// Default constructor
CVisualCalcDlg::CVisualCalcDlg(CWnd* pParent /*=NULL*/)
: CDialog(CVisualCalcDlg::IDD, pParent),
m_strVisualCalcVersion ("2.24") {
//{{AFX_DATA_INIT(CVisualCalcDlg)
//}}AFX_DATA_INIT
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
// For exchanges between controls and data members
void CVisualCalcDlg::DoDataExchange(CDataExchange* pDX) {
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CVisualCalcDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CVisualCalcDlg, CDialog)
//{{AFX_MSG_MAP(CVisualCalcDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_CALC_BTN, OnCalculate)
ON_BN_CLICKED(IDC_ABOUT_BTN, OnAbout)
ON_BN_CLICKED(IDC_HELP_BTN, OnHelp)
ON_BN_CLICKED(IDC_RESETANS_BTN, OnResetAns)
ON_BN_CLICKED(IDC_RESETVARS_BTN, OnResetVars)
ON_BN_CLICKED(IDC_RESETFUNCS_BTN, OnResetFuncs)
ON_LBN_DBLCLK(IDC_ANSLIST_LBOX, OnDblclkAnsList)
ON_LBN_DBLCLK(IDC_FORMULAS_LBOX, OnDblclkFormulasList)
ON_LBN_DBLCLK(IDC_VARNAMES_LBOX, OnDblclkVarList)
ON_LBN_DBLCLK(IDC_VARVALS_LBOX, OnDblclkVarValuesList)
ON_LBN_DBLCLK(IDC_FUNCLIST_LBOX, OnDblclkFuncList)
ON_BN_CLICKED(IDC_ANSLISTSTATE_CHK, OnChangeAnswersListState)
ON_BN_CLICKED(IDC_VARLISTSTATE_CHK, OnChangeVariablesListState)
ON_EN_CHANGE(IDC_INPUT_EDIT, OnChangeInputEdit)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
// Manages the system Menu
void CVisualCalcDlg::OnSysCommand(UINT nID, LPARAM lParam) {
if ((nID & 0xFFF0) == IDM_ABOUTBOX) {
OnAbout();
}
else if ((nID & 0xFFF0) == IDM_HELPBOX) {
OnHelp();
}
else {
CDialog::OnSysCommand(nID, lParam);
}
}
// Draws the system icon of the dialog
void CVisualCalcDlg::OnPaint() {
if (IsIconic()) {
CPaintDC dc(this);
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
dc.DrawIcon(x, y, m_hIcon);
}
else {
CDialog::OnPaint();
}
}
// OnQueryDragIcon()
HCURSOR CVisualCalcDlg::OnQueryDragIcon() {
return (HCURSOR) m_hIcon;
}
/////////////////////////////////////////////////////////////////////////////
// CVisualCalcDlg message handlers
BOOL CVisualCalcDlg::OnInitDialog() {
CDialog::OnInitDialog();
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL) {
CString strAboutMenu, strHelpMenu;
strAboutMenu.Format(IDS_ABOUTBOX, m_strVisualCalcVersion);
strHelpMenu.LoadString(IDS_HELPBOX);
if ((!strAboutMenu.IsEmpty()) && (!strHelpMenu.IsEmpty())) {
pSysMenu->AppendMenu(MF_SEPARATOR);
}
if ((!strAboutMenu.IsEmpty()) && (!strHelpMenu.IsEmpty())) {
pSysMenu->AppendMenu(MF_STRING, IDM_HELPBOX, strHelpMenu);
}
if (!strAboutMenu.IsEmpty()) {
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// Initializes the Controls' pointers...
m_peInput = (CEdit*) GetDlgItem(IDC_INPUT_EDIT);
m_peOutput = (CEdit*) GetDlgItem(IDC_OUTPUT_EDIT);
m_plAnswers = (CListBox*) GetDlgItem(IDC_ANSLIST_LBOX);
m_plFormulas = (CListBox*) GetDlgItem(IDC_FORMULAS_LBOX);
m_plVariables = (CListBox*) GetDlgItem(IDC_VARNAMES_LBOX);
m_plVarValues = (CListBox*) GetDlgItem(IDC_VARVALS_LBOX);
m_plFunctions = (CListBox*) GetDlgItem(IDC_FUNCLIST_LBOX);
m_pbResetAnswers = (CButton*) GetDlgItem(IDC_RESETANS_BTN);
m_pbResetVariables = (CButton*) GetDlgItem(IDC_RESETVARS_BTN);
m_pbResetFunctions = (CButton*) GetDlgItem(IDC_RESETFUNCS_BTN);
m_pbAnswersListState = (CButton*) GetDlgItem(IDC_ANSLISTSTATE_CHK);
m_pbVariablesListState = (CButton*) GetDlgItem(IDC_VARLISTSTATE_CHK);
m_pbCalculate = (CButton*) GetDlgItem(IDC_CALC_BTN);
m_pbAbout = (CButton*) GetDlgItem(IDC_ABOUT_BTN);
m_pbHelp = (CButton*) GetDlgItem(IDC_HELP_BTN);
m_psAnswers = (CStatic*) GetDlgItem(IDC_ANSWERS_STATIC);
m_psVariables = (CStatic*) GetDlgItem(IDC_VARIABLES_STATIC);
m_psFunctions = (CStatic*) GetDlgItem(IDC_FUNCTIONS_STATIC);
m_psVisualCalc = (CStatic*) GetDlgItem(IDC_VISUALCALC_STATIC);
m_psHowToQuit = (CStatic*) GetDlgItem(IDC_HOWTOQUIT_STATIC);
// Sets the Controls' captions...
CString strControlCaption;
strControlCaption.LoadString(IDS_ERASE_BTN); m_pbResetAnswers->SetWindowText(strControlCaption);
m_pbResetVariables->SetWindowText(strControlCaption);
m_pbResetFunctions->SetWindowText(strControlCaption);
strControlCaption.LoadString(IDS_CALCULATE_BTN); m_pbCalculate->SetWindowText(strControlCaption);
strControlCaption.LoadString(IDS_ABOUT_BTN); m_pbAbout->SetWindowText(strControlCaption);
strControlCaption.LoadString(IDS_HELP_BTN); m_pbHelp->SetWindowText(strControlCaption);
strControlCaption.LoadString(IDS_ANSWERS_STC); m_psAnswers->SetWindowText(strControlCaption);
strControlCaption.LoadString(IDS_VARIABLES_STC); m_psVariables->SetWindowText(strControlCaption);
strControlCaption.LoadString(IDS_FUNCTIONS_STC); m_psFunctions->SetWindowText(strControlCaption);
strControlCaption.LoadString(IDS_HOWTOQUIT_STC); m_psHowToQuit->SetWindowText(strControlCaption);
strControlCaption.LoadString(IDS_VISUALCALC); m_psVisualCalc->SetWindowText(strControlCaption);
this->SetWindowText(strControlCaption + " " + m_strVisualCalcVersion);
// Sets the icon on the switch answers lists state button
HICON hIcon;
hIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_SWITCH), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
if (hIcon) {
m_pbAnswersListState->SendMessage(BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);
m_pbVariablesListState->SendMessage(BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);
}
// Initialize the ListBoxes...
this->OnResetAns();
this->OnResetVars();
this->OnResetFuncs();
this->m_peInput->SetFocus();
return FALSE;
}
// Check if the text typed recalls the last answer
void CVisualCalcDlg::OnChangeInputEdit() {
CString strInput;
m_peInput->GetWindowText(strInput);
if ((strInput.GetLength() == 1) && (m_plAnswers->GetCount())) {
CString strNewInput;
switch (strInput[0]) {
case TV_ASSIGN:
strNewInput += " ";
strNewInput += strInput;
strNewInput += " ";
m_peInput->SetWindowText(strNewInput);
m_peOutput->SetWindowText("Warning : Please select a variable to assign before");
m_peInput->SetSel(0, 0);
break;
case TV_PLUS:
case TV_MINUS:
case TV_MUL:
case TV_DIV:
case TV_POW:
case TV_MOD:
case TV_FACT:
strNewInput += "Ans(1) ";
strNewInput += strInput + " ";
m_peInput->SetWindowText(strNewInput);
m_peInput->SetSel(strNewInput.GetLength(), strNewInput.GetLength());
}
}
}
// Opens the About DialogBox...
void CVisualCalcDlg::OnAbout() {
CAboutDlg dlg(m_strVisualCalcVersion, m_Parser.GetVersion().c_str());
dlg.DoModal();
}
// Opens the Help/Catalog DialogBox...
void CVisualCalcDlg::OnHelp() {
CHelpSheetDlg dlg(m_strVisualCalcVersion);
dlg.DoModal();
}
// Double-Click on the Answers ListBox
void CVisualCalcDlg::OnDblclkAnsList() {
CString strAnswer;
m_plAnswers->GetText(m_plAnswers->GetCurSel(), strAnswer);
m_peInput->ReplaceSel(strAnswer);
m_peInput->SetFocus();
}
// Double-Click on the Formulas ListBox
void CVisualCalcDlg::OnDblclkFormulasList() {
CString strAnswer;
m_plFormulas->GetText(m_plFormulas->GetCurSel(), strAnswer);
m_peInput->ReplaceSel(strAnswer);
m_peInput->SetFocus();
}
// Double-Click on the Variables ListBox
void CVisualCalcDlg::OnDblclkVarList() {
CString strVariable;
m_plVariables->GetText(m_plVariables->GetCurSel(), strVariable);
m_peInput->ReplaceSel(strVariable);
m_peInput->SetFocus();
}
// Double-Click on the Variables ListBox
void CVisualCalcDlg::OnDblclkVarValuesList() {
CString strVarValue;
m_plVarValues->GetText(m_plVarValues->GetCurSel(), strVarValue);
m_peInput->ReplaceSel(strVarValue);
m_peInput->SetFocus();
}
// Double-Click on the Functions ListBox
void CVisualCalcDlg::OnDblclkFuncList() {
CString strFunction;
m_plFunctions->GetText(m_plFunctions->GetCurSel(), strFunction);
m_peInput->ReplaceSel(strFunction);
m_peInput->SetFocus();
}
// Updates the content of the Answers History ListBox
void CVisualCalcDlg::UpdateAnswersList() {
// Clears the Answers and Formulas ListBoxes entries
int iNbAnswersToDelete = m_plAnswers->GetCount();
for (int iCpt = 0; iCpt < iNbAnswersToDelete; iCpt++) {
// Both ListBoxes contain the same number of lines
m_plAnswers->DeleteString(0);
m_plFormulas->DeleteString(0);
}
// Retrieves the new parser answers history
const std::deque<AnswerItem> dqeAnswersHistory = m_Parser.GetAnswersHistory();
std::deque<AnswerItem>::const_iterator iter;
char pszHistoryEntry[100];
for (iter = dqeAnswersHistory.begin(); iter != dqeAnswersHistory.end(); iter++) {
::sprintf(pszHistoryEntry, "%.8f", iter->m_valResult);
m_plAnswers->AddString(this->RemoveTrailingZeros(pszHistoryEntry));
m_plFormulas->AddString(iter->m_strFormula.c_str());
}
}
// Updates the content of the Variables ListBox
void CVisualCalcDlg::UpdateVariablesList() {
// Clears the ListBox entries
int iNbVariablesToDelete = m_plVariables->GetCount();
for (int iCpt = 0; iCpt < iNbVariablesToDelete; iCpt++) {
m_plVariables->DeleteString(0);
m_plVarValues->DeleteString(0);
}
// Retrieves the new parser variables list
const std::map<std::string, VALUES_TYPE> mapVariables = m_Parser.GetVariables();
std::map<std::string, VALUES_TYPE>::const_iterator iter;
for (iter = mapVariables.begin(); iter != mapVariables.end(); iter++) {
CString strVarValue;
strVarValue.Format("%.8f", iter->second);
this->RemoveTrailingZeros(strVarValue);
m_plVariables->AddString(iter->first.c_str());
m_plVarValues->AddString(this->RemoveTrailingZeros(strVarValue));
}
}
// Updates the content of the Functions ListBox
void CVisualCalcDlg::UpdateFunctionsList() {
// Clears the ListBox entries
int iNbFunctionsToDelete = m_plFunctions->GetCount();
for (int iCpt = 0; iCpt < iNbFunctionsToDelete; iCpt++) {
m_plFunctions->DeleteString(0);
}
// Retrieves the new parser functions list
const std::list<std::string> lstFunctions = m_Parser.GetFunctions();
std::list<std::string>::const_iterator iter;
for (iter = lstFunctions.begin(); iter != lstFunctions.end(); iter++) {
m_plFunctions->AddString(iter->c_str());
}
}
// Changes the display of the Answers List
void CVisualCalcDlg::OnChangeAnswersListState() {
if (m_pbAnswersListState->GetCheck() == BST_CHECKED) {
m_plAnswers->ShowWindow(SW_HIDE);
m_plFormulas->ShowWindow(SW_SHOW);
}
else {
m_plAnswers->ShowWindow(SW_SHOW);
m_plFormulas->ShowWindow(SW_HIDE);
}
m_peInput->SetFocus();
}
// Changes the display of the Variables List
void CVisualCalcDlg::OnChangeVariablesListState() {
if (m_pbVariablesListState->GetCheck() == BST_CHECKED) {
m_plVariables->ShowWindow(SW_HIDE);
m_plVarValues->ShowWindow(SW_SHOW);
}
else {
m_plVariables->ShowWindow(SW_SHOW);
m_plVarValues->ShowWindow(SW_HIDE);
}
m_peInput->SetFocus();
}
// Simple-Click on the "Erase Answers List" button
void CVisualCalcDlg::OnResetAns() {
// Clears the Parser answers history
m_Parser.ResetAnswersHistory();
// Updates the answers history ListBox
this->UpdateAnswersList();
m_peInput->SetFocus();
}
// Simple-Click on the "Erase Variables List" button
void CVisualCalcDlg::OnResetVars() {
// Clears the Parser variables list
m_Parser.ResetVariables();
// Updates the variables ListBox
this->UpdateVariablesList();
m_peInput->SetFocus();
}
// Simple-Click on the "Erase Functions List" button
void CVisualCalcDlg::OnResetFuncs() {
// Clears the Parser functions list
m_Parser.ResetFunctions();
// Update the functions ListBox
this->UpdateFunctionsList();
m_peInput->SetFocus();
}
// Removes the decimal zeros trailing on the right of the period
CString CVisualCalcDlg::RemoveTrailingZeros(const CString& strResult) {
// We consider here that every characters in the string
// is either a digit or a period
// Searches a '.' in the string
int iDotPosition = -1;
int i = 0;
int j = 1;
CString strNewResult = strResult;
for (; i < strNewResult.GetLength(); i++) {
if (strResult[i] == '.') {
iDotPosition = i;
break;
}
}
// Removes the zeros only if a period was found
if (iDotPosition != -1) {
for (i = strResult.GetLength()-1; i >= 0; i--) {
if (strResult[i] != '0') {
break;
}
}
strNewResult = strNewResult.Mid(0, i + 1);
}
return strNewResult;
}
// Adds a thousand separation space on the left of the period
CString CVisualCalcDlg::InsertThousandSpaces(const CString& strResult) {
// Searches a '.' in the string
int iDotPosition = -1;
int i = 0;
int j = 1;
CString strNewResult = strResult;
for (; i < strNewResult.GetLength(); i++) {
if (strResult[i] == '.') {
iDotPosition = i;
break;
}
}
// If no '.' was found
if (iDotPosition == -1) {
iDotPosition = strNewResult.GetLength();
}
// Inserts a thousand space separator
// (every 3 characters except at the very beginning of the string)
iDotPosition--;
for (i = iDotPosition; i >= 0; i--, j++) {
if (!(j%3) && (i)) {
strNewResult.Insert(i, ' ');
}
}
return strNewResult;
}
///////////////////////////////////////////////////////////////////////////////
// Beginning of the Parser...
void CVisualCalcDlg::OnCalculate() {
CString strSource, strDest;
m_peInput->GetWindowText(strSource);
// Initializes and calls the Parser
try {
VALUES_TYPE valResult = m_Parser.Evaluate((LPCTSTR)strSource);
strDest.Format("%.8f", valResult);
strDest = this->RemoveTrailingZeros(strDest);
strDest = this->InsertThousandSpaces(strDest);
if (m_Parser.HasWarning()) {
// Adds the warning after the result
strDest.Format("%s ; %s", strDest, m_Parser.GetWarningMsg().c_str());
}
m_peInput->SetSel(0, -1);
}
catch (CSyntaxException& ex) {
strDest.Format("Syntax error %d : %s", ex.GetExceptionNumber(), ex.GetMessage().c_str());
m_peInput->SetSel(ex.GetErrorPos(), ex.GetErrorPos());
}
catch (CMathematicException& ex) {
strDest.Format("Mathematic error %d : %s", ex.GetExceptionNumber(), ex.GetMessage().c_str());
m_peInput->SetSel(ex.GetErrorPos(), ex.GetErrorPos());
}
catch (CFunctionException& ex) {
strDest.Format("Function error %d : %s", ex.GetExceptionNumber(), ex.GetMessage().c_str());
m_peInput->SetSel(ex.GetErrorPos(), ex.GetErrorPos());
}
catch (CParameterException& ex) {
strDest.Format("Parameter error %d : %s", ex.GetExceptionNumber(), ex.GetMessage().c_str());
m_peInput->SetSel(ex.GetErrorPos(), ex.GetErrorPos());
}
catch (CVariableException& ex) {
strDest.Format("Variable error %d : %s", ex.GetExceptionNumber(), ex.GetMessage().c_str());
m_peInput->SetSel(ex.GetErrorPos(), ex.GetErrorPos());
}
catch (CDomainException& ex) {
strDest.Format("Domain error %d : %s", ex.GetExceptionNumber(), ex.GetMessage().c_str());
m_peInput->SetSel(ex.GetErrorPos(), ex.GetErrorPos());
}
catch (CParserException& ex) {
strDest.Format("Parser error %d : %s", ex.GetExceptionNumber(), ex.GetMessage().c_str());
m_peInput->SetSel(ex.GetErrorPos(), ex.GetErrorPos());
}
catch (...) {
strDest.Format("Unknown parser internal error");
}
// Prints the result...
m_peOutput->SetWindowText(strDest);
// Updates the listboxes' contents
this->UpdateAnswersList();
this->UpdateVariablesList();
this->UpdateFunctionsList();
// Give the focus back to the input EditBox
m_peInput->SetFocus();
}