954 lines
21 KiB
C++
954 lines
21 KiB
C++
// calculator.cpp
|
|
|
|
//----------------------------------------------------------------------
|
|
// A simple calculator with trigonometric functions
|
|
//----------------------------------------------------------------------
|
|
|
|
#include <cfloat>
|
|
#include <cmath>
|
|
#include <cstdlib>
|
|
#include <limits>
|
|
#include <stack>
|
|
|
|
#include "fapp.h"
|
|
#include "fdialog.h"
|
|
#include "fmessagebox.h"
|
|
|
|
const lDouble PI = 3.141592653589793238L;
|
|
|
|
//----------------------------------------------------------------------
|
|
// class Button
|
|
//----------------------------------------------------------------------
|
|
|
|
#pragma pack(push)
|
|
#pragma pack(1)
|
|
|
|
class Button : public FButton
|
|
{
|
|
private:
|
|
bool checked;
|
|
public:
|
|
explicit Button (FWidget* parent=0); // constructor
|
|
void setChecked(bool);
|
|
void onKeyPress (FKeyEvent*);
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
//----------------------------------------------------------------------
|
|
Button::Button (FWidget* parent) : FButton(parent)
|
|
{
|
|
checked = false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void Button::setChecked(bool on)
|
|
{
|
|
if ( checked != on )
|
|
{
|
|
checked = on;
|
|
|
|
if ( checked )
|
|
{
|
|
setBackgroundColor(fc::Cyan);
|
|
setFocusForegroundColor(fc::White);
|
|
setFocusBackgroundColor(fc::Cyan);
|
|
}
|
|
else
|
|
{
|
|
setBackgroundColor(wc.button_active_bg);
|
|
setFocusForegroundColor(wc.button_active_focus_fg);
|
|
setFocusBackgroundColor(wc.button_active_focus_bg);
|
|
}
|
|
redraw();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void Button::onKeyPress (FKeyEvent* event)
|
|
{
|
|
int key = event->key();
|
|
|
|
// catch the enter key
|
|
if ( key == fc::Fkey_return || key == fc::Fkey_enter )
|
|
return;
|
|
|
|
FButton::onKeyPress(event);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// class Calc
|
|
//----------------------------------------------------------------------
|
|
|
|
#pragma pack(push)
|
|
#pragma pack(1)
|
|
|
|
class Calc : public FDialog
|
|
{
|
|
private:
|
|
bool error;
|
|
bool arcus_mode;
|
|
bool hyperbolic_mode;
|
|
|
|
enum button
|
|
{
|
|
Sine,
|
|
Cosine,
|
|
Tangent,
|
|
Reciprocal,
|
|
On,
|
|
Natural_logarithm,
|
|
Powers_of_e,
|
|
Power,
|
|
Square_root,
|
|
Divide,
|
|
Common_logarithm,
|
|
Powers_of_ten,
|
|
Parenthese_l,
|
|
Parenthese_r,
|
|
Multiply,
|
|
Hyperbolic,
|
|
Seven,
|
|
Eight,
|
|
Nine,
|
|
Subtract,
|
|
Arcus,
|
|
Four,
|
|
Five,
|
|
Six,
|
|
Add,
|
|
Pi,
|
|
One,
|
|
Two,
|
|
Three,
|
|
Percent,
|
|
Zero,
|
|
Decimal_point,
|
|
Change_sign,
|
|
Equals,
|
|
NUM_OF_BUTTONS
|
|
};
|
|
|
|
lDouble a, b;
|
|
uInt max_char;
|
|
int last_key;
|
|
char infix_operator;
|
|
char last_infix_operator;
|
|
FString input;
|
|
int button_no[Calc::NUM_OF_BUTTONS];
|
|
|
|
struct stack_data
|
|
{
|
|
lDouble term;
|
|
char infix_operator;
|
|
};
|
|
|
|
std::stack<stack_data> bracket_stack;
|
|
std::map<Calc::button, Button*> calculator_buttons;
|
|
|
|
private:
|
|
void drawDispay();
|
|
virtual void draw();
|
|
bool isDataEntryKey(int);
|
|
bool isOperatorKey(int);
|
|
void setDisplay (lDouble);
|
|
void setInfixOperator(char);
|
|
void clearInfixOperator();
|
|
void calcInfixOperator();
|
|
|
|
public:
|
|
explicit Calc (FWidget* parent=0); // constructor
|
|
~Calc(); // destructor
|
|
void onKeyPress (FKeyEvent*);
|
|
void onAccel (FAccelEvent*);
|
|
void onClose (FCloseEvent*);
|
|
void cb_buttonClicked (FWidget*, void*);
|
|
|
|
protected:
|
|
void adjustSize();
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
//----------------------------------------------------------------------
|
|
Calc::Calc (FWidget* parent) : FDialog(parent)
|
|
{
|
|
error = false;
|
|
arcus_mode = false;
|
|
hyperbolic_mode = false;
|
|
input = "";
|
|
clearInfixOperator();
|
|
last_infix_operator = '\0';
|
|
max_char = 32;
|
|
last_key = -1;
|
|
a = b = 0.0L;
|
|
|
|
const wchar_t* button_text[Calc::NUM_OF_BUTTONS] =
|
|
{
|
|
L"&Sin",
|
|
L"&Cos",
|
|
L"&Tan",
|
|
L"1/&x",
|
|
L"&On",
|
|
L"L&n",
|
|
L"&e\x02e3",
|
|
L"&y\x02e3",
|
|
L"Sq&r",
|
|
L"&\xf7",
|
|
L"&Lg",
|
|
L"10&\x02e3",
|
|
L"&(",
|
|
L"&)",
|
|
L"&\xd7",
|
|
L"&Hyp",
|
|
L"&7",
|
|
L"&8",
|
|
L"&9",
|
|
L"&-",
|
|
L"&Arc",
|
|
L"&4",
|
|
L"&5",
|
|
L"&6",
|
|
L"&+",
|
|
L"&\x03c0",
|
|
L"&1",
|
|
L"&2",
|
|
L"&3",
|
|
L"&%",
|
|
L"&0",
|
|
L"&.",
|
|
L"&±",
|
|
L"&="
|
|
};
|
|
|
|
setlocale(LC_NUMERIC, "C");
|
|
|
|
setText ("calculator");
|
|
setGeometry (19, 6, 37, 18);
|
|
addAccelerator('q'); // press 'q' to quit
|
|
setShadow();
|
|
|
|
for (int key=0; key < Calc::NUM_OF_BUTTONS; key++)
|
|
{
|
|
Button* btn = new Button(this);
|
|
button_no[key] = key;
|
|
|
|
if ( key == Equals )
|
|
btn->setGeometry(30, 15, 5, 3);
|
|
else
|
|
{
|
|
int x, y, n;
|
|
(key <= Three) ? n=0 : n=1;
|
|
x = (key+n)%5*7 + 2;
|
|
y = (key+n)/5*2 + 3;
|
|
btn->setGeometry(x, y, 5, 1);
|
|
}
|
|
btn->setFlat();
|
|
btn->setNoUnderline();
|
|
btn->setText(button_text[key]);
|
|
btn->setDoubleFlatLine(fc::top);
|
|
if ( isNewFont() )
|
|
btn->unsetClickAnimation();
|
|
if ( key <= Three )
|
|
btn->setDoubleFlatLine(fc::bottom);
|
|
|
|
btn->addCallback
|
|
(
|
|
"clicked",
|
|
this,
|
|
reinterpret_cast<FWidget::FMemberCallback>(&Calc::cb_buttonClicked),
|
|
&button_no[key]
|
|
);
|
|
|
|
calculator_buttons[button(key)] = btn;
|
|
|
|
}
|
|
|
|
calculator_buttons[On]->addAccelerator(fc::Fkey_dc); // del key
|
|
calculator_buttons[On]->setFocus();
|
|
calculator_buttons[Pi]->addAccelerator('p');
|
|
calculator_buttons[Power]->addAccelerator('^');
|
|
calculator_buttons[Divide]->addAccelerator('/');
|
|
calculator_buttons[Powers_of_ten]->addAccelerator('d');
|
|
calculator_buttons[Multiply]->addAccelerator('*');
|
|
calculator_buttons[Decimal_point]->addAccelerator(',');
|
|
calculator_buttons[Change_sign]->addAccelerator('#');
|
|
calculator_buttons[Equals]->addAccelerator(fc::Fkey_return);
|
|
calculator_buttons[Equals]->addAccelerator(fc::Fkey_enter);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
Calc::~Calc()
|
|
{
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void Calc::drawDispay()
|
|
{
|
|
FString display = input;
|
|
setUpdateVTerm(false);
|
|
|
|
if ( display.isNull() || display.isEmpty() )
|
|
display = L'0';
|
|
|
|
if ( display.right(3) == L"-0." )
|
|
display = L'0';
|
|
|
|
if ( display.back() == L'.' && display.getLength() > 1 )
|
|
display = display.left(display.getLength() - 1);
|
|
|
|
if ( ! display.isEmpty() && display.getLength() < max_char )
|
|
display.insert(FString(max_char - display.getLength(), L' '), 0);
|
|
|
|
if ( display.getLength() > max_char )
|
|
display = display.left(max_char);
|
|
|
|
if ( infix_operator )
|
|
display[1] = infix_operator;
|
|
|
|
if ( error )
|
|
display = " Error ";
|
|
|
|
setColor(fc::Black, fc::LightGray);
|
|
gotoxy (xpos+xmin+1, ypos+ymin+1);
|
|
print(display);
|
|
print(L' ');
|
|
|
|
setColor(wc.dialog_fg, wc.dialog_bg);
|
|
if ( isNewFont() )
|
|
{
|
|
FString bottom_line(33, wchar_t(fc::NF_border_line_bottom));
|
|
gotoxy (xpos+xmin+1, ypos+ymin);
|
|
print(bottom_line);
|
|
gotoxy (xpos+xmin+0, ypos+ymin+1);
|
|
print (wchar_t(fc::NF_rev_border_line_right));
|
|
gotoxy (xpos+xmin+34, ypos+ymin+1);
|
|
print (wchar_t(fc::NF_border_line_left));
|
|
FString top_bottom_line_5(5, wchar_t(fc::NF_border_line_up_and_down));
|
|
FString top_line_2(2, wchar_t(fc::NF_border_line_upper));
|
|
gotoxy (xpos+xmin+1, ypos+ymin+2);
|
|
print ( top_bottom_line_5 + top_line_2
|
|
+ top_bottom_line_5 + top_line_2
|
|
+ top_bottom_line_5 + top_line_2
|
|
+ top_bottom_line_5 + top_line_2
|
|
+ top_bottom_line_5);
|
|
}
|
|
else
|
|
{
|
|
FString separator = FString(wchar_t(fc::BoxDrawingsVerticalAndRight))
|
|
+ FString(35, wchar_t(fc::BoxDrawingsHorizontal))
|
|
+ FString(wchar_t(fc::BoxDrawingsVerticalAndLeft));
|
|
gotoxy (xpos+xmin-1, ypos+ymin+2);
|
|
print(separator);
|
|
}
|
|
setUpdateVTerm(true);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void Calc::draw()
|
|
{
|
|
FDialog::draw();
|
|
drawDispay();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
bool Calc::isDataEntryKey (int key)
|
|
{
|
|
// test if key is in {'.', '0'..'9'}
|
|
int data_entry_keys[] =
|
|
{
|
|
Decimal_point,
|
|
Zero,
|
|
One,
|
|
Two,
|
|
Three,
|
|
Four,
|
|
Five,
|
|
Six,
|
|
Seven,
|
|
Eight,
|
|
Nine
|
|
};
|
|
|
|
int* iter = std::find (data_entry_keys, data_entry_keys+11, key);
|
|
|
|
if ( iter != data_entry_keys+11 )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
bool Calc::isOperatorKey(int key)
|
|
{
|
|
// test if key is in {'*', '/', '+', '-', '^', '='}
|
|
int operators[] =
|
|
{
|
|
Multiply,
|
|
Divide,
|
|
Add,
|
|
Subtract,
|
|
Power,
|
|
Equals
|
|
};
|
|
|
|
int* iter = std::find (operators, operators+6, key);
|
|
|
|
if ( iter != operators+6 )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void Calc::setDisplay (lDouble d)
|
|
{
|
|
char buffer[32];
|
|
snprintf (buffer, sizeof(buffer), "%31.11Lg", d);
|
|
input = buffer;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
inline void Calc::setInfixOperator(char c)
|
|
{
|
|
infix_operator = c;
|
|
last_infix_operator = infix_operator;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
inline void Calc::clearInfixOperator()
|
|
{
|
|
infix_operator = '\0';
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void Calc::calcInfixOperator()
|
|
{
|
|
using namespace std;
|
|
|
|
switch ( infix_operator )
|
|
{
|
|
case '*':
|
|
if ( a != 0.0L )
|
|
{
|
|
// ln(a * b) = ln(a) + ln(b)
|
|
if ( log(abs(a)) + log(abs(b)) <= log(LDBL_MAX) )
|
|
a *= b;
|
|
else
|
|
error = true;
|
|
}
|
|
else
|
|
b = 0.0L;
|
|
break;
|
|
|
|
case '/':
|
|
if ( b != 0.0L )
|
|
a /= b;
|
|
else
|
|
error = true;
|
|
break;
|
|
|
|
case '+':
|
|
if ( a != 0.0L )
|
|
{
|
|
if ( log(abs(a)) + log(abs(1 + b/a)) <= log(LDBL_MAX) )
|
|
a += b;
|
|
else
|
|
error = true;
|
|
}
|
|
else
|
|
a = b;
|
|
break;
|
|
|
|
case '-':
|
|
if ( a != 0.0L )
|
|
{
|
|
if ( log(abs(a)) + log(abs(1 - b/a)) <= log(LDBL_MAX) )
|
|
a -= b;
|
|
else
|
|
error = true;
|
|
}
|
|
else
|
|
a = b * (-1.0L);
|
|
break;
|
|
|
|
case '^':
|
|
a = pow(a, b);
|
|
if ( errno == EDOM || errno == ERANGE )
|
|
error = true;
|
|
break;
|
|
}
|
|
clearInfixOperator();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void Calc::onKeyPress (FKeyEvent* event)
|
|
{
|
|
int len = int(input.getLength());
|
|
int key = event->key();
|
|
|
|
switch ( key )
|
|
{
|
|
case fc::Fkey_erase:
|
|
case fc::Fkey_backspace:
|
|
if ( len > 0 )
|
|
{
|
|
if ( len == 1 )
|
|
input = "";
|
|
else
|
|
input = input.left(input.getLength() - 1);
|
|
a = atof(input.c_str());
|
|
drawDispay();
|
|
updateTerminal();
|
|
}
|
|
event->accept();
|
|
break;
|
|
|
|
case fc::Fkey_escape:
|
|
case fc::Fkey_escape_mintty:
|
|
FAccelEvent a_ev(Accelerator_Event, getFocusWidget());
|
|
calculator_buttons[On]->onAccel(&a_ev);
|
|
event->accept();
|
|
break;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void Calc::onAccel (FAccelEvent* ev)
|
|
{
|
|
close();
|
|
ev->accept();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void Calc::onClose (FCloseEvent* event)
|
|
{
|
|
int ret = FMessageBox::info ( this, "Quit",
|
|
"Do you really want\n"
|
|
"to quit the program ?",
|
|
FMessageBox::Yes,
|
|
FMessageBox::No );
|
|
|
|
(ret == FMessageBox::Yes) ? event->accept() : event->ignore();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void Calc::cb_buttonClicked (FWidget*, void* data_ptr)
|
|
{
|
|
int key;
|
|
lDouble* x;
|
|
|
|
using namespace std;
|
|
|
|
if ( infix_operator )
|
|
x = &b;
|
|
else
|
|
x = &a;
|
|
|
|
key = *(static_cast<int*>(data_ptr));
|
|
|
|
switch ( key )
|
|
{
|
|
case Sine: // sin
|
|
if ( hyperbolic_mode )
|
|
{
|
|
if ( arcus_mode )
|
|
{
|
|
*x = log(*x + sqrt((*x) * (*x) + 1));
|
|
if ( errno == EDOM || errno == ERANGE )
|
|
error = true;
|
|
if ( *x == INFINITY )
|
|
error = true;
|
|
}
|
|
else
|
|
*x = sinh(*x);
|
|
}
|
|
else
|
|
{
|
|
if ( arcus_mode )
|
|
*x = asin(*x) * 180.0L/PI;
|
|
else if ( fmod(*x,180.0L) == 0.0L )
|
|
*x = 0.0L;
|
|
else
|
|
*x = sin(*x * PI/180.0L);
|
|
}
|
|
if ( errno == EDOM )
|
|
error = true;
|
|
setDisplay(*x);
|
|
arcus_mode = false;
|
|
hyperbolic_mode = false;
|
|
calculator_buttons[Arcus]->setChecked(false);
|
|
calculator_buttons[Hyperbolic]->setChecked(false);
|
|
break;
|
|
|
|
case Cosine: // cos
|
|
if ( hyperbolic_mode )
|
|
{
|
|
if ( arcus_mode )
|
|
{
|
|
*x = log(*x + sqrt((*x) * (*x) - 1));
|
|
if ( errno == EDOM || errno == ERANGE )
|
|
error = true;
|
|
if ( *x == INFINITY )
|
|
error = true;
|
|
}
|
|
else
|
|
*x = cosh(*x);
|
|
}
|
|
else
|
|
{
|
|
if ( arcus_mode )
|
|
*x = acos(*x) * 180.0L/PI;
|
|
else if ( fmod(*x - 90.0L,180.0L) == 0.0L )
|
|
*x = 0.0L;
|
|
else
|
|
*x = cos(*x * PI/180.0L);
|
|
}
|
|
if ( errno == EDOM )
|
|
error = true;
|
|
setDisplay(*x);
|
|
arcus_mode = false;
|
|
hyperbolic_mode = false;
|
|
calculator_buttons[Arcus]->setChecked(false);
|
|
calculator_buttons[Hyperbolic]->setChecked(false);
|
|
break;
|
|
|
|
case Tangent: // tan
|
|
if ( hyperbolic_mode )
|
|
{
|
|
if ( arcus_mode )
|
|
if ( *x < 1 )
|
|
{
|
|
*x = 0.5L * log((1+(*x))/(1-(*x)));
|
|
if ( errno == EDOM || errno == ERANGE )
|
|
error = true;
|
|
}
|
|
else
|
|
error = true;
|
|
else
|
|
*x = tanh(*x);
|
|
}
|
|
else
|
|
{
|
|
if ( arcus_mode )
|
|
*x = atan(*x) * 180.0L/PI;
|
|
else
|
|
if ( fmod(*x,180.0L) != 0.0L && fmod(*x,90.0L) == 0.0L )
|
|
error = true;
|
|
else if ( fmod(*x,180.0L) == 0.0L )
|
|
*x = 0.0L;
|
|
else
|
|
*x = tan(*x * PI/180.0L);
|
|
}
|
|
if ( errno == EDOM )
|
|
error = true;
|
|
setDisplay(*x);
|
|
arcus_mode = false;
|
|
hyperbolic_mode = false;
|
|
calculator_buttons[Arcus]->setChecked(false);
|
|
calculator_buttons[Hyperbolic]->setChecked(false);
|
|
break;
|
|
|
|
case Reciprocal: // 1/x
|
|
if ( *x == 0.0L )
|
|
error = true;
|
|
else
|
|
{
|
|
*x = 1/(*x);
|
|
setDisplay(*x);
|
|
}
|
|
break;
|
|
|
|
case On:
|
|
error = false;
|
|
arcus_mode = false;
|
|
hyperbolic_mode = false;
|
|
calculator_buttons[Arcus]->setChecked(false);
|
|
calculator_buttons[Hyperbolic]->setChecked(false);
|
|
input = "";
|
|
clearInfixOperator();
|
|
last_infix_operator = '\0';
|
|
a = b = 0.0L;
|
|
break;
|
|
|
|
case Natural_logarithm: // ln
|
|
*x = log(*x);
|
|
if ( errno == EDOM || errno == ERANGE )
|
|
error = true;
|
|
setDisplay(*x);
|
|
break;
|
|
|
|
case Powers_of_e: // eˣ
|
|
*x = exp(*x);
|
|
if ( errno == ERANGE )
|
|
error = true;
|
|
setDisplay(*x);
|
|
break;
|
|
|
|
case Power: // yˣ
|
|
if ( ! isOperatorKey(last_key) )
|
|
calcInfixOperator();
|
|
setDisplay(*x);
|
|
setInfixOperator('^');
|
|
break;
|
|
|
|
case Square_root: // sqrt
|
|
*x = sqrt(*x);
|
|
if ( errno == EDOM || errno == ERANGE )
|
|
error = true;
|
|
setDisplay(*x);
|
|
break;
|
|
|
|
case Divide: // ÷
|
|
if ( ! isOperatorKey(last_key) )
|
|
calcInfixOperator();
|
|
setDisplay(a);
|
|
setInfixOperator('/');
|
|
break;
|
|
|
|
case Common_logarithm: // lg
|
|
*x = log10(*x);
|
|
if ( errno == EDOM || errno == ERANGE )
|
|
error = true;
|
|
setDisplay(*x);
|
|
break;
|
|
|
|
case Powers_of_ten: // 10ˣ
|
|
*x = pow(10,*x);
|
|
if ( errno == EDOM || errno == ERANGE )
|
|
error = true;
|
|
setDisplay(*x);
|
|
break;
|
|
|
|
case Parenthese_l: // (
|
|
{
|
|
stack_data d = { a, infix_operator };
|
|
bracket_stack.push(d);
|
|
clearInfixOperator();
|
|
input = "";
|
|
a = b = 0.0L;
|
|
setDisplay(a);
|
|
}
|
|
break;
|
|
|
|
case Parenthese_r: // )
|
|
if ( ! bracket_stack.empty() )
|
|
{
|
|
calcInfixOperator();
|
|
setDisplay(a);
|
|
stack_data d = bracket_stack.top();
|
|
bracket_stack.pop();
|
|
b = d.term;
|
|
infix_operator = d.infix_operator;
|
|
last_infix_operator = infix_operator;
|
|
}
|
|
break;
|
|
|
|
case Multiply: // *
|
|
if ( ! isOperatorKey(last_key) )
|
|
calcInfixOperator();
|
|
setDisplay(a);
|
|
setInfixOperator('*');
|
|
break;
|
|
|
|
case Hyperbolic: // hyp
|
|
hyperbolic_mode = ! hyperbolic_mode;
|
|
calculator_buttons[Hyperbolic]->setChecked(hyperbolic_mode);
|
|
setDisplay(*x);
|
|
break;
|
|
|
|
case Seven: // 7
|
|
if ( input.getLength() < max_char )
|
|
{
|
|
if ( isDataEntryKey(last_key) )
|
|
input += '7';
|
|
else
|
|
input = '7';
|
|
}
|
|
break;
|
|
|
|
case Eight: // 8
|
|
if ( input.getLength() < max_char )
|
|
{
|
|
if ( isDataEntryKey(last_key) )
|
|
input += '8';
|
|
else
|
|
input = '8';
|
|
}
|
|
break;
|
|
|
|
case Nine: // 9
|
|
if ( input.getLength() < max_char )
|
|
{
|
|
if ( isDataEntryKey(last_key) )
|
|
input += '9';
|
|
else
|
|
input = '9';
|
|
}
|
|
break;
|
|
|
|
case Subtract: // -
|
|
if ( ! isOperatorKey(last_key) )
|
|
calcInfixOperator();
|
|
setDisplay(a);
|
|
setInfixOperator('-');
|
|
break;
|
|
|
|
case Arcus: // arc
|
|
arcus_mode = ! arcus_mode;
|
|
calculator_buttons[Arcus]->setChecked(arcus_mode);
|
|
setDisplay(*x);
|
|
break;
|
|
|
|
case Four: // 4
|
|
if ( input.getLength() < max_char )
|
|
{
|
|
if ( isDataEntryKey(last_key) )
|
|
input += '4';
|
|
else
|
|
input = '4';
|
|
}
|
|
break;
|
|
|
|
case Five: // 5
|
|
if ( input.getLength() < max_char )
|
|
{
|
|
if ( isDataEntryKey(last_key) )
|
|
input += '5';
|
|
else
|
|
input = '5';
|
|
}
|
|
break;
|
|
|
|
case Six: // 6
|
|
if ( input.getLength() < max_char )
|
|
{
|
|
if ( isDataEntryKey(last_key) )
|
|
input += '6';
|
|
else
|
|
input = '6';
|
|
}
|
|
break;
|
|
|
|
case Add: // +
|
|
if ( ! isOperatorKey(last_key) )
|
|
calcInfixOperator();
|
|
setDisplay(a);
|
|
setInfixOperator('+');
|
|
break;
|
|
|
|
case Pi: // π
|
|
*x = PI;
|
|
setDisplay(*x);
|
|
break;
|
|
|
|
case One: // 1
|
|
if ( input.getLength() < max_char )
|
|
{
|
|
if ( isDataEntryKey(last_key) )
|
|
input += '1';
|
|
else
|
|
input = '1';
|
|
}
|
|
break;
|
|
|
|
case Two: // 2
|
|
if ( input.getLength() < max_char )
|
|
{
|
|
if ( isDataEntryKey(last_key) )
|
|
input += '2';
|
|
else
|
|
input = '2';
|
|
}
|
|
break;
|
|
|
|
case Three: // 3
|
|
if ( input.getLength() < max_char )
|
|
{
|
|
if ( isDataEntryKey(last_key) )
|
|
input += '3';
|
|
else
|
|
input = '3';
|
|
}
|
|
break;
|
|
|
|
case Percent: // %
|
|
infix_operator = last_infix_operator;
|
|
*x /= 100.0L;
|
|
setDisplay(*x);
|
|
break;
|
|
|
|
case Zero: // 0
|
|
if ( input.getLength() < max_char )
|
|
{
|
|
if ( isDataEntryKey(last_key) )
|
|
input += '0';
|
|
else
|
|
input = '0';
|
|
}
|
|
break;
|
|
|
|
case Decimal_point: // .
|
|
if ( ! input.includes('.') )
|
|
input += '.';
|
|
break;
|
|
|
|
case Change_sign: // ±
|
|
*x *= -1.0L;
|
|
setDisplay(*x);
|
|
break;
|
|
|
|
case Equals: // =
|
|
infix_operator = last_infix_operator;
|
|
calcInfixOperator();
|
|
setDisplay(a);
|
|
break;
|
|
} // end of switch
|
|
|
|
if ( ! input.isEmpty() )
|
|
{
|
|
if ( isDataEntryKey(key) )
|
|
*x = input.toDouble();
|
|
else
|
|
{
|
|
// remove trailing zeros
|
|
while ( ! input.includes(L'e')
|
|
&& input.includes(L'.')
|
|
&& input.back() == L'0' )
|
|
input = input.left(input.getLength()-1);
|
|
}
|
|
}
|
|
|
|
drawDispay();
|
|
updateTerminal();
|
|
|
|
if ( infix_operator && ! isDataEntryKey(key) )
|
|
input = "";
|
|
last_key = key;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void Calc::adjustSize()
|
|
{
|
|
int pw = parentWidget()->getWidth();
|
|
int ph = parentWidget()->getHeight();
|
|
setX (1 + (pw - getWidth()) / 2, false);
|
|
setY (1 + (ph - getHeight()) / 2, false);
|
|
FDialog::adjustSize();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// main part
|
|
//----------------------------------------------------------------------
|
|
int main (int argc, char* argv[])
|
|
{
|
|
// Create the application object
|
|
FApplication app(argc, argv);
|
|
|
|
// Create a calculator object
|
|
Calc calculator(&app);
|
|
|
|
app.setMainWidget(&calculator);
|
|
calculator.show();
|
|
return app.exec();
|
|
}
|