aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Scipione <jscipione@gmail.com>2012-07-30 22:35:57 -0400
committerJohn Scipione <jscipione@gmail.com>2012-07-30 22:35:57 -0400
commit8ffd0477dd4998324e051800da35cadd91a7fb8c (patch)
tree7722d8e22558811cd949942fbf9ee5c67724d1f8
parent93aac98d0a9b8ce27f94eb449cfc742446a50274 (diff)
Implement degree mode in DeskCalc.hrev44442
Default is radian mode, You set the option in the right click menu like the other options. Note: degree mode does not affect hyperbolic trigonometric functions. This is how Mac Calculator, Windows Calculator, and Google Calculator work.
-rw-r--r--headers/private/shared/ExpressionParser.h6
-rw-r--r--src/apps/deskcalc/CalcOptions.cpp8
-rw-r--r--src/apps/deskcalc/CalcOptions.h1
-rw-r--r--src/apps/deskcalc/CalcView.cpp24
-rw-r--r--src/apps/deskcalc/CalcView.h8
-rw-r--r--src/apps/deskcalc/CalcWindow.cpp4
-rw-r--r--src/kits/shared/ExpressionParser.cpp50
7 files changed, 98 insertions, 3 deletions
diff --git a/headers/private/shared/ExpressionParser.h b/headers/private/shared/ExpressionParser.h
index 9c835b3e93..4778b29559 100644
--- a/headers/private/shared/ExpressionParser.h
+++ b/headers/private/shared/ExpressionParser.h
@@ -42,6 +42,9 @@ class ExpressionParser {
ExpressionParser();
~ExpressionParser();
+ bool DegreeMode();
+ void SetDegreeMode(bool degrees);
+
void SetSupportHexInput(bool enabled);
BString Evaluate(const char* expressionString);
@@ -49,7 +52,6 @@ class ExpressionParser {
double EvaluateToDouble(const char* expressionString);
private:
-
MAPM _ParseBinary();
MAPM _ParseSum();
MAPM _ParseProduct();
@@ -64,6 +66,8 @@ class ExpressionParser {
void _EatToken(int32 type);
Tokenizer* fTokenizer;
+
+ bool fDegreeMode;
};
#endif // EXPRESSION_PARSER_H
diff --git a/src/apps/deskcalc/CalcOptions.cpp b/src/apps/deskcalc/CalcOptions.cpp
index b737f4d704..3b353798cf 100644
--- a/src/apps/deskcalc/CalcOptions.cpp
+++ b/src/apps/deskcalc/CalcOptions.cpp
@@ -20,6 +20,7 @@ CalcOptions::CalcOptions()
:
auto_num_lock(false),
audio_feedback(false),
+ degree_mode(false),
keypad_mode(KEYPAD_MODE_BASIC)
{
}
@@ -37,6 +38,9 @@ CalcOptions::LoadSettings(const BMessage* archive)
if (archive->FindBool("audio feedback", &option) == B_OK)
audio_feedback = option;
+ if (archive->FindBool("degree mode", &option) == B_OK)
+ degree_mode = option;
+
if (archive->FindUInt8("keypad mode", &keypad_mode_option) == B_OK)
keypad_mode = keypad_mode_option;
}
@@ -51,8 +55,10 @@ CalcOptions::SaveSettings(BMessage* archive) const
ret = archive->AddBool("audio feedback", audio_feedback);
if (ret == B_OK)
+ ret = archive->AddBool("degree mode", degree_mode);
+
+ if (ret == B_OK)
ret = archive->AddUInt8("keypad mode", keypad_mode);
return ret;
}
-
diff --git a/src/apps/deskcalc/CalcOptions.h b/src/apps/deskcalc/CalcOptions.h
index 1eb013dddb..2fb45a0455 100644
--- a/src/apps/deskcalc/CalcOptions.h
+++ b/src/apps/deskcalc/CalcOptions.h
@@ -24,6 +24,7 @@ class BMessage;
struct CalcOptions {
bool auto_num_lock; // automatically activate numlock
bool audio_feedback; // provide audio feedback
+ bool degree_mode; // radian or degree mode
uint8 keypad_mode; // keypad mode options
CalcOptions();
diff --git a/src/apps/deskcalc/CalcView.cpp b/src/apps/deskcalc/CalcView.cpp
index bab5c923ad..eba3f4f414 100644
--- a/src/apps/deskcalc/CalcView.cpp
+++ b/src/apps/deskcalc/CalcView.cpp
@@ -244,6 +244,10 @@ CalcView::MessageReceived(BMessage* message)
case MSG_OPTIONS_AUDIO_FEEDBACK:
ToggleAudioFeedback();
return;
+
+ case MSG_OPTIONS_ANGLE_MODE:
+ ToggleAngleMode();
+ return;
}
}
@@ -931,6 +935,7 @@ CalcView::Evaluate()
try {
ExpressionParser parser;
+ parser.SetDegreeMode(fOptions->degree_mode);
value = parser.Evaluate(expression.String());
} catch (ParseException e) {
BString error(e.message.String());
@@ -970,6 +975,16 @@ CalcView::ToggleAudioFeedback(void)
fAudioFeedbackItem->SetMarked(fOptions->audio_feedback);
}
+
+void
+CalcView::ToggleAngleMode(void)
+{
+ fOptions->degree_mode = !fOptions->degree_mode;
+ fAngleModeRadianItem->SetMarked(!fOptions->degree_mode);
+ fAngleModeDegreeItem->SetMarked(fOptions->degree_mode);
+}
+
+
void
CalcView::SetKeypadMode(uint8 mode)
{
@@ -1257,6 +1272,10 @@ CalcView::_CreatePopUpMenu(bool addKeypadModeMenuItems)
new BMessage(MSG_OPTIONS_AUTO_NUM_LOCK));
fAudioFeedbackItem = new BMenuItem(B_TRANSLATE("Audio Feedback"),
new BMessage(MSG_OPTIONS_AUDIO_FEEDBACK));
+ fAngleModeRadianItem = new BMenuItem(B_TRANSLATE("Radian Mode"),
+ new BMessage(MSG_OPTIONS_ANGLE_MODE));
+ fAngleModeDegreeItem = new BMenuItem(B_TRANSLATE("Degree Mode"),
+ new BMessage(MSG_OPTIONS_ANGLE_MODE));
if (addKeypadModeMenuItems) {
fKeypadModeCompactItem = new BMenuItem(B_TRANSLATE("Compact"),
new BMessage(MSG_OPTIONS_KEYPAD_MODE_COMPACT), '0');
@@ -1269,6 +1288,8 @@ CalcView::_CreatePopUpMenu(bool addKeypadModeMenuItems)
// apply current settings
fAutoNumlockItem->SetMarked(fOptions->auto_num_lock);
fAudioFeedbackItem->SetMarked(fOptions->audio_feedback);
+ fAngleModeRadianItem->SetMarked(!fOptions->degree_mode);
+ fAngleModeDegreeItem->SetMarked(fOptions->degree_mode);
// construct menu
fPopUpMenu = new BPopUpMenu("pop-up", false, false);
@@ -1277,6 +1298,9 @@ CalcView::_CreatePopUpMenu(bool addKeypadModeMenuItems)
// TODO: Enable this when we use beep events which can be configured
// in the Sounds preflet.
//fPopUpMenu->AddItem(fAudioFeedbackItem);
+ fPopUpMenu->AddSeparatorItem();
+ fPopUpMenu->AddItem(fAngleModeRadianItem);
+ fPopUpMenu->AddItem(fAngleModeDegreeItem);
if (addKeypadModeMenuItems) {
fPopUpMenu->AddSeparatorItem();
fPopUpMenu->AddItem(fKeypadModeCompactItem);
diff --git a/src/apps/deskcalc/CalcView.h b/src/apps/deskcalc/CalcView.h
index 16cf413727..2c61fe7dc2 100644
--- a/src/apps/deskcalc/CalcView.h
+++ b/src/apps/deskcalc/CalcView.h
@@ -16,6 +16,7 @@
enum {
MSG_OPTIONS_AUTO_NUM_LOCK = 'oanl',
MSG_OPTIONS_AUDIO_FEEDBACK = 'oafb',
+ MSG_OPTIONS_ANGLE_MODE = 'oamd',
MSG_OPTIONS_KEYPAD_MODE_COMPACT = 'okmc',
MSG_OPTIONS_KEYPAD_MODE_BASIC = 'okmb',
MSG_OPTIONS_KEYPAD_MODE_SCIENTIFIC = 'okms',
@@ -90,6 +91,9 @@ class CalcView : public BView {
// (option currently disabled)
void ToggleAudioFeedback(void);
+ // Toggle radian/degree mode
+ void ToggleAngleMode(void);
+
// Set the keypad mode
void SetKeypadMode(uint8 mode);
@@ -147,6 +151,10 @@ class CalcView : public BView {
BPopUpMenu* fPopUpMenu;
BMenuItem* fAutoNumlockItem;
BMenuItem* fAudioFeedbackItem;
+
+ BMenuItem* fAngleModeRadianItem;
+ BMenuItem* fAngleModeDegreeItem;
+
BMenuItem* fKeypadModeCompactItem;
BMenuItem* fKeypadModeBasicItem;
BMenuItem* fKeypadModeScientificItem;
diff --git a/src/apps/deskcalc/CalcWindow.cpp b/src/apps/deskcalc/CalcWindow.cpp
index 0ccb142af3..f91d0d49fc 100644
--- a/src/apps/deskcalc/CalcWindow.cpp
+++ b/src/apps/deskcalc/CalcWindow.cpp
@@ -88,6 +88,10 @@ CalcWindow::MessageReceived(BMessage* message)
fCalcView->ToggleAudioFeedback();
break;
+ case MSG_OPTIONS_ANGLE_MODE:
+ fCalcView->ToggleAngleMode();
+ break;
+
case MSG_OPTIONS_KEYPAD_MODE_COMPACT:
fCalcView->SetKeypadMode(KEYPAD_MODE_COMPACT);
break;
diff --git a/src/kits/shared/ExpressionParser.cpp b/src/kits/shared/ExpressionParser.cpp
index 6622433089..4ea2387703 100644
--- a/src/kits/shared/ExpressionParser.cpp
+++ b/src/kits/shared/ExpressionParser.cpp
@@ -338,7 +338,8 @@ class Tokenizer {
ExpressionParser::ExpressionParser()
- : fTokenizer(new Tokenizer())
+ : fTokenizer(new Tokenizer()),
+ fDegreeMode(false)
{
}
@@ -349,6 +350,20 @@ ExpressionParser::~ExpressionParser()
}
+bool
+ExpressionParser::DegreeMode()
+{
+ return fDegreeMode;
+}
+
+
+void
+ExpressionParser::SetDegreeMode(bool degrees)
+{
+ fDegreeMode = degrees;
+}
+
+
void
ExpressionParser::SetSupportHexInput(bool enabled)
{
@@ -594,19 +609,36 @@ ExpressionParser::_ParseFunction(const Token& token)
return _ParseFactorial(values[0].abs());
} else if (strcasecmp("acos", token.string.String()) == 0) {
_InitArguments(values, 1);
+ if (fDegreeMode)
+ values[0] = values[0] * MM_PI / 180;
+
if (values[0] < -1 || values[0] > 1)
throw ParseException("out of domain", token.position);
+
return _ParseFactorial(values[0].acos());
} else if (strcasecmp("asin", token.string.String()) == 0) {
_InitArguments(values, 1);
+ if (fDegreeMode)
+ values[0] = values[0] * MM_PI / 180;
+
if (values[0] < -1 || values[0] > 1)
throw ParseException("out of domain", token.position);
+
return _ParseFactorial(values[0].asin());
} else if (strcasecmp("atan", token.string.String()) == 0) {
_InitArguments(values, 1);
+ if (fDegreeMode)
+ values[0] = values[0] * MM_PI / 180;
+
return _ParseFactorial(values[0].atan());
} else if (strcasecmp("atan2", token.string.String()) == 0) {
_InitArguments(values, 2);
+
+ if (fDegreeMode) {
+ values[0] = values[0] * MM_PI / 180;
+ values[1] = values[1] * MM_PI / 180;
+ }
+
return _ParseFactorial(values[0].atan2(values[1]));
} else if (strcasecmp("cbrt", token.string.String()) == 0) {
_InitArguments(values, 1);
@@ -616,9 +648,13 @@ ExpressionParser::_ParseFunction(const Token& token)
return _ParseFactorial(values[0].ceil());
} else if (strcasecmp("cos", token.string.String()) == 0) {
_InitArguments(values, 1);
+ if (fDegreeMode)
+ values[0] = values[0] * MM_PI / 180;
+
return _ParseFactorial(values[0].cos());
} else if (strcasecmp("cosh", token.string.String()) == 0) {
_InitArguments(values, 1);
+ // This function always uses radians
return _ParseFactorial(values[0].cosh());
} else if (strcasecmp("exp", token.string.String()) == 0) {
_InitArguments(values, 1);
@@ -630,34 +666,46 @@ ExpressionParser::_ParseFunction(const Token& token)
_InitArguments(values, 1);
if (values[0] <= 0)
throw ParseException("out of domain", token.position);
+
return _ParseFactorial(values[0].log());
} else if (strcasecmp("log", token.string.String()) == 0) {
_InitArguments(values, 1);
if (values[0] <= 0)
throw ParseException("out of domain", token.position);
+
return _ParseFactorial(values[0].log10());
} else if (strcasecmp("pow", token.string.String()) == 0) {
_InitArguments(values, 2);
return _ParseFactorial(values[0].pow(values[1]));
} else if (strcasecmp("sin", token.string.String()) == 0) {
_InitArguments(values, 1);
+ if (fDegreeMode)
+ values[0] = values[0] * MM_PI / 180;
+
return _ParseFactorial(values[0].sin());
} else if (strcasecmp("sinh", token.string.String()) == 0) {
_InitArguments(values, 1);
+ // This function always uses radians
return _ParseFactorial(values[0].sinh());
} else if (strcasecmp("sqrt", token.string.String()) == 0) {
_InitArguments(values, 1);
if (values[0] < 0)
throw ParseException("out of domain", token.position);
+
return _ParseFactorial(values[0].sqrt());
} else if (strcasecmp("tan", token.string.String()) == 0) {
_InitArguments(values, 1);
+ if (fDegreeMode)
+ values[0] = values[0] * MM_PI / 180;
+
MAPM divided_by_half_pi = values[0] / MM_HALF_PI;
if (divided_by_half_pi.is_integer() && divided_by_half_pi.is_odd())
throw ParseException("out of domain", token.position);
+
return _ParseFactorial(values[0].tan());
} else if (strcasecmp("tanh", token.string.String()) == 0) {
_InitArguments(values, 1);
+ // This function always uses radians
return _ParseFactorial(values[0].tanh());
}