diff --git a/src/apps/deskcalc/CalcOptionsWindow.cpp b/src/apps/deskcalc/CalcOptionsWindow.cpp index f72418b8cf..5175d814b1 100644 --- a/src/apps/deskcalc/CalcOptionsWindow.cpp +++ b/src/apps/deskcalc/CalcOptionsWindow.cpp @@ -20,11 +20,46 @@ CalcOptions::CalcOptions() : auto_num_lock(true), - audio_feedback(false) + audio_feedback(false), + show_keypad(true) { } +void +CalcOptions::LoadSettings(const BMessage* archive) +{ + bool option; + + if (archive->FindBool("auto num lock", &option) == B_OK) + auto_num_lock = option; + + if (archive->FindBool("audio feedback", &option) == B_OK) + audio_feedback = option; + + if (archive->FindBool("show keypad", &option) == B_OK) + show_keypad = option; +} + + +status_t +CalcOptions::SaveSettings(BMessage* archive) const +{ + status_t ret = archive->AddBool("auto num lock", auto_num_lock); + + if (ret == B_OK) + ret = archive->AddBool("audio feedback", audio_feedback); + + if (ret == B_OK) + ret = archive->AddBool("show keypad", show_keypad); + + return ret; +} + + +// #pragma mark - + + CalcOptionsWindow::CalcOptionsWindow(BRect frame, CalcOptions *options, BMessage* quitMessage, BHandler* target) @@ -44,6 +79,8 @@ CalcOptionsWindow::CalcOptionsWindow(BRect frame, CalcOptions *options, // create interface components float y = 16.0f, vw, vh; + + // auto numlock BRect viewframe(4.0f, y, frame.right, y + 16.0f); fAutoNumLockCheckBox = new BCheckBox(viewframe, "autoNumLockCheckBox", "Auto Num Lock", NULL); @@ -53,7 +90,8 @@ CalcOptionsWindow::CalcOptionsWindow(BRect frame, CalcOptions *options, bg->AddChild(fAutoNumLockCheckBox); fAutoNumLockCheckBox->ResizeToPreferred(); y += fAutoNumLockCheckBox->Frame().Height(); - + + // audio feedback viewframe.Set(4.0f, y, frame.right, y + 16.0f); fAudioFeedbackCheckBox = new BCheckBox(viewframe, "audioFeedbackCheckBox", "Audio Feedback", NULL); @@ -63,17 +101,29 @@ CalcOptionsWindow::CalcOptionsWindow(BRect frame, CalcOptions *options, bg->AddChild(fAudioFeedbackCheckBox); fAudioFeedbackCheckBox->ResizeToPreferred(); y += fAudioFeedbackCheckBox->Frame().Height(); + + // show keypad + viewframe.Set(4.0f, y, frame.right, y + 16.0f); + fShowKeypadCheckBox = new BCheckBox(viewframe, + "showKeypadCheckBox", "Show Keypad", NULL); + if (fOptions->show_keypad) { + fShowKeypadCheckBox->SetValue(B_CONTROL_ON); + } + bg->AddChild(fShowKeypadCheckBox); + fShowKeypadCheckBox->ResizeToPreferred(); + y += fShowKeypadCheckBox->Frame().Height(); // create buttons viewframe.Set(0.0f, 0.0f, 40.0f, 40.0f); fOkButton = new BButton(viewframe, "okButton", "OK", new BMessage(B_QUIT_REQUESTED)); - fOkButton->MakeDefault(true); fOkButton->GetPreferredSize(&vw, &vh); fOkButton->ResizeTo(vw, vh); fOkButton->MoveTo(frame.right - vw - 8.0f, frame.bottom - vh - 8.0f); bg->AddChild(fOkButton); + + fOkButton->MakeDefault(true); float cw, ch; fCancelButton = new BButton(viewframe, "cancelButton", "Cancel", @@ -101,6 +151,9 @@ CalcOptionsWindow::QuitRequested() // audio feedback fOptions->audio_feedback = fAudioFeedbackCheckBox->Value() == B_CONTROL_ON; + // show keypad + fOptions->show_keypad = fShowKeypadCheckBox->Value() == B_CONTROL_ON; + // notify target of our demise if (fQuitMessage && fTarget && fTarget->Looper()) { fQuitMessage->AddRect("window frame", Frame()); diff --git a/src/apps/deskcalc/CalcOptionsWindow.h b/src/apps/deskcalc/CalcOptionsWindow.h index 45697fe8ec..f785c01f8b 100644 --- a/src/apps/deskcalc/CalcOptionsWindow.h +++ b/src/apps/deskcalc/CalcOptionsWindow.h @@ -16,8 +16,12 @@ struct CalcOptions { bool auto_num_lock; // automatically activate numlock bool audio_feedback; // provide audio feedback + bool show_keypad; // show or hide the buttons - CalcOptions(); + CalcOptions(); + + void LoadSettings(const BMessage* archive); + status_t SaveSettings(BMessage* archive) const; }; class BCheckBox; @@ -41,6 +45,8 @@ class CalcOptionsWindow : public BWindow { BCheckBox* fAutoNumLockCheckBox; BCheckBox* fAudioFeedbackCheckBox; + BCheckBox* fShowKeypadCheckBox; + BButton* fOkButton; BButton* fCancelButton; }; diff --git a/src/apps/deskcalc/CalcView.cpp b/src/apps/deskcalc/CalcView.cpp index 059f6ff003..a9fabf7d6f 100644 --- a/src/apps/deskcalc/CalcView.cpp +++ b/src/apps/deskcalc/CalcView.cpp @@ -27,6 +27,7 @@ #include "CalcApplication.h" #include "CalcOptionsWindow.h" +#include "ExpressionTextView.h" #include "Parser.h" @@ -66,7 +67,7 @@ CalcView *CalcView::Instantiate(BMessage *archive) CalcView::CalcView(BRect frame, rgb_color rgbBaseColor) - : BView(frame, "calc-view", B_FOLLOW_ALL_SIDES, + : BView(frame, "DeskCalc", B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS), fColums(5), fRows(4), @@ -74,22 +75,25 @@ CalcView::CalcView(BRect frame, rgb_color rgbBaseColor) fBaseColor(rgbBaseColor), fExpressionBGColor((rgb_color){ 0, 0, 0, 255 }), - fWidth(frame.Width()), - fHeight(frame.Height()), + fWidth(1), + fHeight(1), fKeypadDescription(strdup(kDefaultKeypadDescription)), fKeypad(NULL), - fExpression(""), - fAboutItem(NULL), fOptionsItem(NULL), fPopUpMenu(NULL), fOptions(new CalcOptions()), fOptionsWindow(NULL), - fOptionsWindowFrame(30.0, 50.0, 230.0, 200.0) + fOptionsWindowFrame(30.0, 50.0, 230.0, 200.0), + fShowKeypad(true) { + // create expression text view + fExpressionTextView = new ExpressionTextView(_ExpressionRect(), this); + AddChild(fExpressionTextView); + // tell the app server not to erase our b/g SetViewColor(B_TRANSPARENT_32_BIT); @@ -112,27 +116,28 @@ CalcView::CalcView(BMessage* archive) fBaseColor((rgb_color){ 128, 128, 128, 255 }), fExpressionBGColor((rgb_color){ 0, 0, 0, 255 }), + fWidth(1), + fHeight(1), + fKeypadDescription(strdup(kDefaultKeypadDescription)), fKeypad(NULL), - fExpression(""), - fAboutItem(NULL), fOptionsItem(NULL), fPopUpMenu(NULL), fOptions(new CalcOptions()), fOptionsWindow(NULL), - fOptionsWindowFrame(30.0, 50.0, 230.0, 200.0) + fOptionsWindowFrame(30.0, 50.0, 230.0, 200.0), + fShowKeypad(true) { + // create expression text view + fExpressionTextView = new ExpressionTextView(_ExpressionRect(), this); + AddChild(fExpressionTextView); + // read data from archive LoadSettings(archive); - // load frame dimensions - BRect frame = Frame(); - fWidth = frame.Width(); - fHeight = frame.Height(); - // create pop-up menu system _CreatePopUpMenu(); } @@ -146,6 +151,16 @@ CalcView::~CalcView() } +void +CalcView::AttachedToWindow() +{ + SetFont(be_bold_font); + + BRect frame(Frame()); + FrameResized(frame.Width(), frame.Height()); +} + + void CalcView::MessageReceived(BMessage* message) { @@ -211,6 +226,8 @@ CalcView::MessageReceived(BMessage* message) BRect frame; if (message->FindRect("window frame", &frame) == B_OK) fOptionsWindowFrame = frame; + + _ShowKeypad(fOptions->show_keypad); break; } @@ -225,38 +242,15 @@ CalcView::MessageReceived(BMessage* message) void CalcView::Draw(BRect updateRect) { - rgb_color rgbWhite = { 255, 255, 255, 0 }; + if (!fShowKeypad) + return; // calculate grid sizes - float sizeDisp = fHeight * K_DISPLAY_YPROP; + BRect keypadRect(_KeypadRect()); + float sizeDisp = keypadRect.top; float sizeCol = fWidth / (float)fColums; float sizeRow = (fHeight - sizeDisp) / (float)fRows; - - // setup areas - BRect displayRect(0.0, 0.0, fWidth, sizeDisp); - BRect keypadRect(0.0, sizeDisp, fWidth, fHeight); - - SetFont(be_bold_font); - - // ****** DISPLAY Area - if (updateRect.Intersects(displayRect)) { - // paint display b/g - SetHighColor(fExpressionBGColor); - FillRect(updateRect & displayRect); - - // render display text - SetHighColor(rgbWhite); - SetLowColor(fExpressionBGColor); - SetDrawingMode(B_OP_COPY); - SetFontSize(sizeDisp * K_FONT_YPROP); - float baselineOffset = sizeDisp * (1.0 - K_FONT_YPROP) * 0.5; - DrawString(fExpression.String(), - BPoint(fWidth - StringWidth(fExpression.String()), - sizeDisp - baselineOffset)); - } - - // ****** KEYPAD Area if (updateRect.Intersects(keypadRect)) { // TODO: support pressed keys @@ -301,10 +295,10 @@ CalcView::Draw(BRect updateRect) // render key symbols float halfSizeCol = sizeCol * 0.5f; - SetHighColor(rgbWhite); + SetHighColor(fButtonTextColor); SetLowColor(fBaseColor); SetDrawingMode(B_OP_COPY); - SetFontSize(((fHeight - sizeDisp)/(float)fRows) * K_FONT_YPROP); + SetFontSize(((fHeight - sizeDisp) / (float)fRows) * K_FONT_YPROP); float baselineOffset = ((fHeight - sizeDisp) / (float)fRows) * (1.0 - K_FONT_YPROP) * 0.5; CalcKey *key = fKeypad; @@ -347,25 +341,25 @@ CalcView::MouseDown(BPoint point) // click on display, initiate drag if appropriate if ((point.y - sizeDisp) < 0.0) { // only drag if there's some text - if (fExpression.Length() > 0) { - // assemble drag message - BMessage dragmsg(B_MIME_DATA); - dragmsg.AddData("text/plain", - B_MIME_TYPE, - fExpression.String(), - fExpression.Length()); - - // initiate drag & drop - SetFontSize(sizeDisp * K_FONT_YPROP); - float left = fWidth; - float textWidth = StringWidth(fExpression.String()); - if (textWidth < fWidth) - left -= textWidth; - else - left = 0; - BRect displayRect(left, 0.0, fWidth, sizeDisp); - DragMessage(&dragmsg, displayRect); - } +// if (fExpression.Length() > 0) { +// // assemble drag message +// BMessage dragmsg(B_MIME_DATA); +// dragmsg.AddData("text/plain", +// B_MIME_TYPE, +// fExpression.String(), +// fExpression.Length()); +// +// // initiate drag & drop +// SetFontSize(sizeDisp * K_FONT_YPROP); +// float left = fWidth; +// float textWidth = StringWidth(fExpression.String()); +// if (textWidth < fWidth) +// left -= textWidth; +// else +// left = 0; +// BRect displayRect(left, 0.0, fWidth, sizeDisp); +// DragMessage(&dragmsg, displayRect); +// } } else { // click on keypad @@ -407,7 +401,7 @@ CalcView::KeyDown(const char *bytes, int32 numBytes) case B_SPACE: case B_ESCAPE: - case 'c': // hack! + case 'c': // translate to clear key _PressKey("C"); break; @@ -426,7 +420,7 @@ CalcView::KeyDown(const char *bytes, int32 numBytes) default: { // scan the keymap array for match int keys = fRows * fColums; - for (int i=0; iMakeFocus(focused); } @@ -460,6 +454,24 @@ CalcView::FrameResized(float width, float height) { fWidth = width; fHeight = height; + + // layout expression text view + BRect frame = _ExpressionRect(); + fExpressionTextView->MoveTo(frame.LeftTop()); + fExpressionTextView->ResizeTo(frame.Width(), frame.Height()); + + frame.OffsetTo(B_ORIGIN); + frame.InsetBy(2, 2); + fExpressionTextView->SetTextRect(frame); + + // configure expression text view font size and color + float sizeDisp = fShowKeypad ? fHeight * K_DISPLAY_YPROP : fHeight; + BFont font(be_bold_font); + font.SetSize(sizeDisp * K_FONT_YPROP); + fExpressionTextView->SetViewColor(fExpressionBGColor); + fExpressionTextView->SetLowColor(fExpressionBGColor); + fExpressionTextView->SetFontAndColor(&font, B_FONT_ALL, &fExpressionTextColor); +// fExpressionTextView->SetAlignment(B_ALIGN_RIGHT); } @@ -478,9 +490,12 @@ CalcView::AboutRequested() status_t CalcView::Archive(BMessage* archive, bool deep) const { + fExpressionTextView->RemoveSelf(); + // passed on request to parent status_t ret = BView::Archive(archive, deep); + const_cast(this)->AddChild(fExpressionTextView); // save app signature for replicant add-on loading if (ret == B_OK) @@ -502,9 +517,7 @@ void CalcView::Cut() { Copy(); // copy data to clipboard - fExpression.SetTo(""); // remove data - - _InvalidateExpression(); + fExpressionTextView->Clear(); // remove data } @@ -517,10 +530,11 @@ CalcView::Copy() BMessage *clipper = be_clipboard->Data(); clipper->what = B_MIME_DATA; // TODO: should check return for errors! + BString expression = fExpressionTextView->Text(); clipper->AddData("text/plain", B_MIME_TYPE, - fExpression.String(), - fExpression.Length()); + expression.String(), + expression.Length()); //clipper->PrintToStream(); be_clipboard->Commit(); be_clipboard->Unlock(); @@ -564,8 +578,9 @@ CalcView::Paste(BMessage *message) B_MIME_TYPE, (const void**)&text, &numBytes) == B_OK) { - fExpression.Append(text, numBytes); - _InvalidateExpression(); + BString temp; + temp.Append(text, numBytes); + fExpressionTextView->Insert(temp.String()); } } } @@ -614,14 +629,7 @@ CalcView::LoadSettings(BMessage* archive) } // load options - const CalcOptions* options; - if (archive->FindData("options", B_RAW_TYPE, - (const void**)&options, &size) == B_OK - && size == sizeof(CalcOptions)) { - memcpy(fOptions, options, size); - } else { - puts("Missing options from CalcView archive.\n"); - } + fOptions->LoadSettings(archive); // load option window frame BRect frame; @@ -634,7 +642,7 @@ CalcView::LoadSettings(BMessage* archive) puts("Missing display text from CalcView archive.\n"); } else { // init expression text - fExpression = display; + fExpressionTextView->SetText(display); } // parse calculator description @@ -668,8 +676,7 @@ CalcView::SaveSettings(BMessage* archive) const // record current options if (ret == B_OK) - ret = archive->AddData("options", B_RAW_TYPE, - fOptions, sizeof(CalcOptions)); + ret = fOptions->SaveSettings(archive); // record option window frame if (ret == B_OK) @@ -677,7 +684,7 @@ CalcView::SaveSettings(BMessage* archive) const // record display text if (ret == B_OK) - ret = archive->AddString("displayText", fExpression.String()); + ret = archive->AddString("displayText", fExpressionTextView->Text()); // record calculator description if (ret == B_OK) @@ -687,6 +694,92 @@ CalcView::SaveSettings(BMessage* archive) const } +void +CalcView::Evaluate() +{ + const double EXP_SWITCH_HI = 1e12; // # digits to switch from std->exp form + const double EXP_SWITCH_LO = 1e-12; + + BString expression = fExpressionTextView->Text(); + expression << "\n"; + + if (expression.Length() == 0) { + beep(); + return; + } + + // audio feedback + if (fOptions->audio_feedback) { + BEntry zimp("zimp.AIFF"); + entry_ref zimp_ref; + zimp.GetRef(&zimp_ref); + play_sound(&zimp_ref, true, false, false); + } + +//printf("evaluate: %s\n", expression.String()); + + // evaluate expression + Expression parser; + + char* tmpstr = strdup(expression.String()); + char* start = tmpstr; + char* end = start + expression.Length() - 1; + double value = 0.0; + + try { + value = parser.Evaluate(start, end, true); + } catch (const char* error) { + fExpressionTextView->SetText(error); + return; + } + + free(tmpstr); + +//printf(" -> value: %f\n", value); + + // beautify the expression + // TODO: see if this is necessary at all + char buf[64]; + if (value == 0) { + strcpy(buf, "0"); + } else if (((value < EXP_SWITCH_HI) && (value > EXP_SWITCH_LO)) || + ((value > -EXP_SWITCH_HI) && (value < -EXP_SWITCH_LO))) { + // print in std form + sprintf(buf, "%9f", value); + + // hack to remove surplus zeros! + if (strchr(buf, '.')) { + int32 i = strlen(buf) - 1; + for (; i > 0; i--) { + if (buf[i] == '0') + buf[i] = '\0'; + else + break; + } + if (buf[i] == '.') + buf[i] = '\0'; + } + } else { + // print in exponential form + sprintf(buf, "%e", value); + } + + // render new result to display + fExpressionTextView->SetExpression(buf); +} + + +void +CalcView::FlashKey(const char* bytes, int32 numBytes) +{ + BString temp; + temp.Append(bytes, numBytes); + int32 key = _KeyForLabel(temp.String()); + if (key >= 0) + _FlashKey(key); +} + + // #pragma mark - @@ -697,37 +790,37 @@ CalcView::_ParseCalcDesc(const char* keypadDescription) fKeypad = new CalcKey[fRows * fColums]; // scan through calculator description and assemble keypad - bool scanFlag = true; CalcKey *key = fKeypad; const char *p = keypadDescription; - while (scanFlag) { + + while (*p != 0) { // copy label char *l = key->label; while (!isspace(*p)) *l++ = *p++; *l = '\0'; - + // set code if (strcmp(key->label, "=") == 0) strcpy(key->code, "\n"); else strcpy(key->code, key->label); - + // set keymap - if (strlen(key->label)==1) { + if (strlen(key->label) == 1) { strcpy(key->keymap, key->label); } else { *key->keymap = '\0'; } // end if - + + // add this to the expression text view, so that it + // will forward the respective KeyDown event to us + fExpressionTextView->AddKeypadLabel(key->label); + // advance while (isspace(*p)) ++p; key++; - - // check desc termination - if (*p == '\0') - scanFlag = false; } } @@ -740,24 +833,18 @@ CalcView::_PressKey(int key) // check for backspace if (strcmp(fKeypad[key].label, "BS") == 0) { - int32 length = fExpression.Length(); - if (length > 0) { - fExpression.Remove(length - 1, 1); - } else { - beep(); - return; // no need to redraw - } + fExpressionTextView->BackSpace(); } else if (strcmp(fKeypad[key].label, "C") == 0) { // C means clear - fExpression.SetTo(""); + fExpressionTextView->Clear(); } else { - // append to display text - fExpression.Append(fKeypad[key].code); - // check for evaluation order if (fKeypad[key].code[0] == '\n') { - _Evaluate(); + Evaluate(); } else { + // insert into expression text + fExpressionTextView->Insert(fKeypad[key].code); + // audio feedback if (fOptions->audio_feedback) { BEntry zimp("key.AIFF"); @@ -769,20 +856,36 @@ CalcView::_PressKey(int key) } // redraw display - _InvalidateExpression(); +// _InvalidateExpression(); } void -CalcView::_PressKey(char *label) +CalcView::_PressKey(const char *label) +{ + int32 key = _KeyForLabel(label); + if (key >= 0) + _PressKey(key); +} + + +int32 +CalcView::_KeyForLabel(const char *label) const { int keys = fRows * fColums; for (int i = 0; i < keys; i++) { if (strcmp(fKeypad[i].label, label) == 0) { - _PressKey(i); - return; + return i; } } + return -1; +} + + +void +CalcView::_FlashKey(int32 key) +{ + // TODO ... } @@ -799,83 +902,21 @@ CalcView::_Colorize() fDarkColor.green = (uint8)(fBaseColor.green * 0.75); fDarkColor.blue = (uint8)(fBaseColor.blue * 0.75); fDarkColor.alpha = 255; -} + // keypad text color + uint8 lightness = (fBaseColor.red + fBaseColor.green + fBaseColor.blue) / 3; + if (lightness > 200) + fButtonTextColor = (rgb_color){ 0, 0, 0, 255 }; + else + fButtonTextColor = (rgb_color){ 255, 255, 255, 255 }; -void -CalcView::_Evaluate() -{ - const double EXP_SWITCH_HI = 1e12; // # digits to switch from std->exp form - const double EXP_SWITCH_LO = 1e-12; - - if (fExpression.Length() == 0) { - beep(); - return; - } - - // audio feedback - if (fOptions->audio_feedback) { - BEntry zimp("zimp.AIFF"); - entry_ref zimp_ref; - zimp.GetRef(&zimp_ref); - play_sound(&zimp_ref, true, false, false); - } - -//printf("evaluate: %s\n", fExpression.String()); - - // evaluate expression - Expression parser; - - char* tmpstr = strdup(fExpression.String()); - char* start = tmpstr; - char* end = start + fExpression.Length() - 1; - double value = 0.0; - - try { - value = parser.Eval(start, end, true); - - } catch (const char* error) { - fExpression = error; - _InvalidateExpression(); - return; - } - - free(tmpstr); - -//printf(" -> value: %f\n", value); - - // beautify the expression - // TODO: see if this is necessary at all - char buf[64]; - if (value == 0) { - strcpy(buf, "0"); - } else if (((value < EXP_SWITCH_HI) && (value > EXP_SWITCH_LO)) || - ((value > -EXP_SWITCH_HI) && (value < -EXP_SWITCH_LO))) { - // print in std form - sprintf(buf, "%9lf", value); - - // hack to remove surplus zeros! - if (strchr(buf, '.')) { - int32 i = strlen(buf) - 1; - for (; i > 0; i--) { - if (buf[i] == '0') - buf[i] = '\0'; - else - break; - } - if (buf[i] == '.') - buf[i] = '\0'; - } - } else { - // print in exponential form - sprintf(buf, "%le", value); - } - - // render new result to display - fExpression = buf; - - // redraw display - _InvalidateExpression(); + // expression text color + lightness = (fExpressionBGColor.red + + fExpressionBGColor.green + fExpressionBGColor.blue) / 3; + if (lightness > 200) + fExpressionTextColor = (rgb_color){ 0, 0, 0, 255 }; + else + fExpressionTextColor = (rgb_color){ 255, 255, 255, 255 }; } @@ -895,11 +936,47 @@ CalcView::_CreatePopUpMenu() } -void -CalcView::_InvalidateExpression() +BRect +CalcView::_ExpressionRect() const { - float sizeDisp = fHeight * K_DISPLAY_YPROP; - BRect displayRect(0.0, 0.0, fWidth, sizeDisp); - Invalidate(displayRect); + BRect r(0.0, 0.0, fWidth, fHeight); + if (fShowKeypad) { + r.bottom = floorf(fHeight * K_DISPLAY_YPROP); + } + return r; } + +BRect +CalcView::_KeypadRect() const +{ + BRect r(0.0, 0.0, -1.0, -1.0); + if (fShowKeypad) { + r.right = fWidth; + r.bottom = fHeight; + r.top = floorf(fHeight * K_DISPLAY_YPROP) + 1; + } + return r; +} + + +void +CalcView::_ShowKeypad(bool show) +{ + if (fShowKeypad == show) + return; + + fShowKeypad = show; + + float height = fShowKeypad ? fHeight / K_DISPLAY_YPROP + : fHeight * K_DISPLAY_YPROP; + + BWindow* window = Window(); + if (window->Bounds() == Frame()) + window->ResizeTo(fWidth, height); + else + ResizeTo(fWidth, height); +} + + + diff --git a/src/apps/deskcalc/CalcView.h b/src/apps/deskcalc/CalcView.h index 37e6b437ce..86cbb9c601 100644 --- a/src/apps/deskcalc/CalcView.h +++ b/src/apps/deskcalc/CalcView.h @@ -12,12 +12,12 @@ #define _CALC_VIEW_H #include -#include class BString; class BMenuItem; class CalcOptions; class CalcOptionsWindow; +class ExpressionTextView; _EXPORT class CalcView : public BView { @@ -33,7 +33,7 @@ class CalcView : public BView { virtual ~CalcView(); - + virtual void AttachedToWindow(); virtual void MessageReceived(BMessage* message); virtual void Draw(BRect updateRect); virtual void MouseDown(BPoint point); @@ -60,18 +60,30 @@ class CalcView : public BView { status_t LoadSettings(BMessage* archive); status_t SaveSettings(BMessage* archive) const; + void Evaluate(); + + void FlashKey(const char* bytes, int32 numBytes); + + void AddExpressionToHistory(const char* expression); + void PreviousExpression(); + void NextExpression(); + private: void _ParseCalcDesc(const char* keypadDescription); void _PressKey(int key); - void _PressKey(char* label); + void _PressKey(const char* label); + int32 _KeyForLabel(const char* label) const; + void _FlashKey(int32 key); void _Colorize(); - void _Evaluate(); - void _CreatePopUpMenu(); - void _InvalidateExpression(); + + BRect _ExpressionRect() const; + BRect _KeypadRect() const; + + void _ShowKeypad(bool show); // grid dimensions int16 fColums; @@ -81,7 +93,9 @@ class CalcView : public BView { rgb_color fBaseColor; rgb_color fLightColor; rgb_color fDarkColor; + rgb_color fButtonTextColor; rgb_color fExpressionBGColor; + rgb_color fExpressionTextColor; // view dimensions float fWidth; @@ -93,8 +107,8 @@ class CalcView : public BView { char* fKeypadDescription; CalcKey* fKeypad; - // display text - BString fExpression; + // expression + ExpressionTextView* fExpressionTextView; // pop-up context menu. BMenuItem* fAboutItem; @@ -105,6 +119,7 @@ class CalcView : public BView { CalcOptions* fOptions; CalcOptionsWindow* fOptionsWindow; BRect fOptionsWindowFrame; + bool fShowKeypad; }; #endif // _CALC_VIEW_H diff --git a/src/apps/deskcalc/ExpressionTextView.cpp b/src/apps/deskcalc/ExpressionTextView.cpp new file mode 100644 index 0000000000..61f4f412d1 --- /dev/null +++ b/src/apps/deskcalc/ExpressionTextView.cpp @@ -0,0 +1,212 @@ +/* + * Copyright 2006 Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#include "ExpressionTextView.h" + +#include + +#include +#include + +#include "CalcView.h" + +using std::nothrow; + +static const int32 kMaxPreviousExpressions = 20; + + +ExpressionTextView::ExpressionTextView(BRect frame, CalcView* calcView) + : InputTextView(frame, "expression text view", + (frame.OffsetToCopy(B_ORIGIN)).InsetByCopy(2, 2), + B_FOLLOW_NONE, B_WILL_DRAW), + fCalcView(calcView), + fKeypadLabels(""), + fPreviousExpressions(20) +{ + SetFont(be_bold_font); +// SetAlignment(B_ALIGN_RIGHT); + SetStylable(false); + SetDoesUndo(true); + SetColorSpace(B_RGB32); +} + + +ExpressionTextView::~ExpressionTextView() +{ + int32 count = fPreviousExpressions.CountItems(); + for (int32 i = 0; i < count; i++) + delete (BString*)fPreviousExpressions.ItemAtFast(i); +} + + +void +ExpressionTextView::MakeFocus(bool focused = true) +{ + if (focused == IsFocus()) { + // stop endless loop when CalcView calls us again + return; + } + + // NOTE: order of lines important! + InputTextView::MakeFocus(focused); + fCalcView->MakeFocus(focused); +} + + +void +ExpressionTextView::KeyDown(const char* bytes, int32 numBytes) +{ + // handle expression history + if (bytes[0] == B_UP_ARROW) { + PreviousExpression(); + return; + } + if (bytes[0] == B_DOWN_ARROW) { + NextExpression(); + return; + } + + // handle in InputTextView, except B_TAB + if (bytes[0] != B_TAB) + InputTextView::KeyDown(bytes, numBytes); + + // pass on to CalcView if this was a label on a key + if (fKeypadLabels.FindFirst(bytes[0]) >= 0) + fCalcView->FlashKey(bytes, numBytes); + + // as soon as something is typed, we are at the + // end of the expression history + fHistoryPos = fPreviousExpressions.CountItems(); +} + + +void +ExpressionTextView::MouseDown(BPoint where) +{ + uint32 buttons; + Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons); + if (buttons & B_PRIMARY_MOUSE_BUTTON) { + InputTextView::MouseDown(where); + return; + } + where = ConvertToParent(where); + fCalcView->MouseDown(where); +} + + +// #pragma mark - + + +void +ExpressionTextView::RevertChanges() +{ + Clear(); +} + + +void +ExpressionTextView::ApplyChanges() +{ + AddExpressionToHistory(Text()); + fCalcView->Evaluate(); +} + + +void +ExpressionTextView::AddKeypadLabel(const char* label) +{ + fKeypadLabels << label; +} + + +void +ExpressionTextView::SetExpression(const char* expression) +{ + SetText(expression); + int32 lastPos = strlen(expression); + Select(lastPos, lastPos); +} + + +void +ExpressionTextView::BackSpace() +{ + if (Window()) + Window()->PostMessage(B_UNDO, this); +} + + +void +ExpressionTextView::Clear() +{ + SetText(""); +} + + +// #pragma mark - + + +void +ExpressionTextView::AddExpressionToHistory(const char* expression) +{ + BString* item = new (nothrow) BString(expression); + if (!item) + return; + if (!fPreviousExpressions.AddItem(item)) { + delete item; + return; + } + while (fPreviousExpressions.CountItems() > kMaxPreviousExpressions) + delete (BString*)fPreviousExpressions.RemoveItem(0L); + + fHistoryPos = fPreviousExpressions.CountItems(); +} + + +void +ExpressionTextView::PreviousExpression() +{ + int32 count = fPreviousExpressions.CountItems(); + if (fHistoryPos == count) { + // save current expression + fCurrentExpression = Text(); + } + + fHistoryPos--; + if (fHistoryPos < 0) { + fHistoryPos = 0; + return; + } + + BString* item = (BString*)fPreviousExpressions.ItemAt(fHistoryPos); + if (item) + SetExpression(item->String()); +} + + +void +ExpressionTextView::NextExpression() +{ + int32 count = fPreviousExpressions.CountItems(); + + fHistoryPos++; + if (fHistoryPos == count) { + SetExpression(fCurrentExpression.String()); + return; + } + + if (fHistoryPos > count) { + fHistoryPos = count; + return; + } + + BString* item = (BString*)fPreviousExpressions.ItemAt(fHistoryPos); + if (item) + SetExpression(item->String()); +} + diff --git a/src/apps/deskcalc/ExpressionTextView.h b/src/apps/deskcalc/ExpressionTextView.h new file mode 100644 index 0000000000..6cd02b3782 Binary files /dev/null and b/src/apps/deskcalc/ExpressionTextView.h differ diff --git a/src/apps/deskcalc/InputTextView.cpp b/src/apps/deskcalc/InputTextView.cpp new file mode 100644 index 0000000000..6db540da57 --- /dev/null +++ b/src/apps/deskcalc/InputTextView.cpp @@ -0,0 +1,163 @@ +/* + * Copyright 2006 Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#include "InputTextView.h" + +#include +#include + +#include + +// constructor +InputTextView::InputTextView(BRect frame, const char* name, + BRect textRect, + uint32 resizingMode, + uint32 flags) + : BTextView(frame, name, textRect, resizingMode, flags), + fWasFocus(false) +{ + SetWordWrap(false); +} + +// destructor +InputTextView::~InputTextView() +{ +} + +// MouseDown +void +InputTextView::MouseDown(BPoint where) +{ + // enforce the behaviour of a typical BTextControl + // only let the BTextView handle mouse up/down when + // it already had focus + fWasFocus = IsFocus(); + if (fWasFocus) { + BTextView::MouseDown(where); + } else { + // forward click + if (BView* view = Parent()) { + view->MouseDown(ConvertToParent(where)); + } + } +} + +// MouseUp +void +InputTextView::MouseUp(BPoint where) +{ + // enforce the behaviour of a typical BTextControl + // only let the BTextView handle mouse up/down when + // it already had focus + if (fWasFocus) + BTextView::MouseUp(where); +} + +// KeyDown +void +InputTextView::KeyDown(const char* bytes, int32 numBytes) +{ + bool handled = true; + if (numBytes > 0) { + switch (bytes[0]) { + case B_ESCAPE: + // revert any typing changes + RevertChanges(); + break; + case B_TAB: + // skip BTextView implementation + BView::KeyDown(bytes, numBytes); + // fall through + case B_RETURN: + ApplyChanges(); + break; + default: + handled = false; + break; + } + } + if (!handled) + BTextView::KeyDown(bytes, numBytes); +} + +// MakeFocus +void +InputTextView::MakeFocus(bool focus) +{ + if (focus != IsFocus()) { + if (BView* view = Parent()) + view->Invalidate(); + BTextView::MakeFocus(focus); + if (focus) + SelectAll(); + ApplyChanges(); + } +} + +// Invoke +status_t +InputTextView::Invoke(BMessage* message) +{ + if (!message) + message = Message(); + + if (message) { + BMessage copy(*message); + copy.AddInt64("when", system_time()); + copy.AddPointer("source", (BView*)this); + return BInvoker::Invoke(©); + } + return B_BAD_VALUE; +} + +// #pragma mark - + +// Select +void +InputTextView::Select(int32 start, int32 finish) +{ + BTextView::Select(start, finish); + + _CheckTextRect(); +} + +// InsertText +void +InputTextView::InsertText(const char* inText, int32 inLength, int32 inOffset, + const text_run_array* inRuns) +{ + BTextView::InsertText(inText, inLength, inOffset, inRuns); + + _CheckTextRect(); +} + +// DeleteText +void +InputTextView::DeleteText(int32 fromOffset, int32 toOffset) +{ + BTextView::DeleteText(fromOffset, toOffset); + + _CheckTextRect(); +} + +// #pragma mark - + +// _CheckTextRect +void +InputTextView::_CheckTextRect() +{ + // update text rect and make sure + // the cursor/selection is in view + BRect textRect(TextRect()); + float width = ceilf(StringWidth(Text()) + 2.0); + if (textRect.Width() < width) { + textRect.right = textRect.left + width; + SetTextRect(textRect); + ScrollToSelection(); + } +} diff --git a/src/apps/deskcalc/InputTextView.h b/src/apps/deskcalc/InputTextView.h new file mode 100644 index 0000000000..7e3d083755 --- /dev/null +++ b/src/apps/deskcalc/InputTextView.h @@ -0,0 +1,57 @@ +/* + * Copyright 2006 Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#ifndef INPUT_TEXT_VIEW_H +#define INPUT_TEXT_VIEW_H + +#include +#include + +class InputTextView : public BTextView, + public BInvoker { + public: + InputTextView(BRect frame, + const char* name, + BRect textRect, + uint32 resizingMode, + uint32 flags); + virtual ~InputTextView(); + + // BTextView interface + virtual void MouseDown(BPoint where); + virtual void MouseUp(BPoint where); + + virtual void KeyDown(const char* bytes, int32 numBytes); + virtual void MakeFocus(bool focus); + + // BInvoker interface + virtual status_t Invoke(BMessage* message = NULL); + + // InputTextView + virtual void RevertChanges() = 0; + virtual void ApplyChanges() = 0; + +protected: + // BTextView + virtual void Select(int32 start, int32 finish); + + virtual void InsertText(const char* inText, + int32 inLength, + int32 inOffset, + const text_run_array* inRuns); + virtual void DeleteText(int32 fromOffset, + int32 toOffset); + + void _CheckTextRect(); + + bool fWasFocus; +}; + +#endif // INPUT_TEXT_VIEW_H + + diff --git a/src/apps/deskcalc/Jamfile b/src/apps/deskcalc/Jamfile index 90de5b4801..f45d4ee05f 100644 --- a/src/apps/deskcalc/Jamfile +++ b/src/apps/deskcalc/Jamfile @@ -10,6 +10,8 @@ Application DeskCalc : CalcView.cpp CalcWindow.cpp DeskCalc.cpp + ExpressionTextView.cpp + InputTextView.cpp Parser.cpp : be $(TARGET_LIBSTDC++) media : DeskCalc.rdef diff --git a/src/apps/deskcalc/Parser.cpp b/src/apps/deskcalc/Parser.cpp index 0b1d4067fb..889b3c849c 100644 --- a/src/apps/deskcalc/Parser.cpp +++ b/src/apps/deskcalc/Parser.cpp @@ -19,934 +19,901 @@ using namespace std; //LineParser::LineParser(istream *stream): -// m_stream(stream), -// m_currentLine(0) +// m_stream(stream), +// m_currentLine(0) //{ //} // //void LineParser::AddSeparator(const char c) //{ -// m_separators.push_back(c); +// m_separators.push_back(c); //} // //size_t LineParser::SetToNext(bool toUpperCase) //{ -// m_line.erase(m_line.begin(), m_line.end()); -// m_unparsed.assign(""); +// m_line.erase(m_line.begin(), m_line.end()); +// m_unparsed.assign(""); // -// // Skip newlines -// while (m_stream->peek() == 0xA || m_stream->peek() == 0xD) -// m_stream->get(); +// // Skip newlines +// while (m_stream->peek() == 0xA || m_stream->peek() == 0xD) +// m_stream->get(); // -// while (!m_stream->eof() && !m_stream->fail() && m_stream->peek() != 0xA && m_stream->peek() != 0xD) -// { -// string param; +// while (!m_stream->eof() && !m_stream->fail() && m_stream->peek() != 0xA && m_stream->peek() != 0xD) +// { +// string param; // -// // Skip whitespaces -// while (m_stream->peek() == ' ' || m_stream->peek() == '\t') +// // Skip whitespaces +// while (m_stream->peek() == ' ' || m_stream->peek() == '\t') // m_unparsed.append(1, char(m_stream->get())); -//// m_separators.push_back(c); add check for separators !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +//// m_separators.push_back(c); add check for separators !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // -// if (m_stream->peek() == '"') +// if (m_stream->peek() == '"') // { -// // Skip first " -// m_unparsed.append(1, char(m_stream->get())); +// // Skip first " +// m_unparsed.append(1, char(m_stream->get())); // -// int c; -// // Read until " -// while (!m_stream->fail() && m_stream->peek() != 0xA && m_stream->peek() != 0xD && +// int c; +// // Read until " +// while (!m_stream->fail() && m_stream->peek() != 0xA && m_stream->peek() != 0xD && // (c = m_stream->get()) != '"' && !m_stream->eof()) -// { -// m_unparsed.append(1, char(c)); -// if (toUpperCase) +// { +// m_unparsed.append(1, char(c)); +// if (toUpperCase) // param.append(1, char(toupper(c))); -// else +// else // param.append(1, char(c)); -// } -// if (c == '"') -// m_unparsed.append(1, char(c)); +// } +// if (c == '"') +// m_unparsed.append(1, char(c)); // } -// else +// else // { -// int c; -// // Read until whitespace -//// m_separators.push_back(c); add check for separators !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// while (!m_stream->fail() && m_stream->peek() != 0xA && m_stream->peek() != 0xD && +// int c; +// // Read until whitespace +//// m_separators.push_back(c); add check for separators !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// while (!m_stream->fail() && m_stream->peek() != 0xA && m_stream->peek() != 0xD && // (c = m_stream->get()) != ' ' && c != '\t' && !m_stream->eof()) -// { -// m_unparsed.append(1, char(c)); -// if (toUpperCase) +// { +// m_unparsed.append(1, char(c)); +// if (toUpperCase) // param.append(1, char(toupper(c))); -// else +// else // param.append(1, char(c)); -// } -// if (c == ' ') -// m_unparsed.append(1, char(c)); +// } +// if (c == ' ') +// m_unparsed.append(1, char(c)); // } // -// // Store parameter -// if (param.size()) +// // Store parameter +// if (param.size()) // m_line.push_back(param); -// } +// } // -// // Skip newlines -// while (m_stream->peek() == 0xA || m_stream->peek() == 0xD) -// m_stream->get(); +// // Skip newlines +// while (m_stream->peek() == 0xA || m_stream->peek() == 0xD) +// m_stream->get(); // -// return m_line.size(); +// return m_line.size(); //} // //void LineParser::WriteCompressed(string *s) const //{ -// size_t i; -// for (i = 0; i < m_line.size(); i++) -// { -// if (i != 0) +// size_t i; +// for (i = 0; i < m_line.size(); i++) +// { +// if (i != 0) // { -// *s += " "; +// *s += " "; // } -// *s += m_line[i]; -// } +// *s += m_line[i]; +// } //} // //void LineParser::WriteCompressed(ostream *stream) const //{ -// size_t i; -// for (i = 0; i < m_line.size(); i++) -// { -// if (i != 0) +// size_t i; +// for (i = 0; i < m_line.size(); i++) +// { +// if (i != 0) // { -// *stream << " "; +// *stream << " "; // } -// *stream << m_line[i]; -// } -// *stream << endl; +// *stream << m_line[i]; +// } +// *stream << endl; //} // //size_t LineParser::ParsedLines() const //{ -// return m_currentLine; +// return m_currentLine; //} // //const char *LineParser::Param(const size_t param) const //{ -// return m_line[param].c_str(); +// return m_line[param].c_str(); //} // //const char *LineParser::Line() const //{ -// return m_unparsed.c_str(); +// return m_unparsed.c_str(); //} -// Expression -double Expression::valtod(const char *exp, const char **end) +// NOTE: commented because unused + +//template +//class MemBlock { +// public: +// MemBlock() +// : fSize(0), +// fBuffer(NULL) +// {} +// +// MemBlock(const MemBlock& src) +// : fSize(0), +// fBuffer(NULL) +// { +// if (src.fBuffer) { +// SetSize(src.fSize); +// memcpy(fBuffer, src.fBuffer, src.fSize); +// } +// } +// +// MemBlock& operator=(const MemBlock& src) +// { +// if (this != &src) { +// SetSize(src.fSize); +// if (fBuffer) +// memcpy(fBuffer, src.fBuffer, src.fSize); +// } +// return (*this); +// } +// +// ~MemBlock() +// { +// free(fBuffer); +// } +// +// void SetSize(const size_t size) +// { +// size_t oldsize = Size(); +// if (oldsize != size) { +// if (!fBuffer && size) { +// fBuffer = malloc(size); +// if (!fBuffer) +// throw "Out of memory"; +// } else if (fBuffer && size) { +// void *newBuf = realloc(fBuffer, size); +// if (newBuf) +// fBuffer = newBuf; +// else +// throw "Out of memory"; +// } else if (fBuffer && !size) { +// free(fBuffer); +// fBuffer = 0; +// } +// fSize = size; +// } +// } +// void* Buffer() const { return fBuffer; } +// T* Access() const { return (T*)fBuffer; } +// T& operator[](size_t i) const +// { +// return Access()[i]; +// } +// size_t Size() const { return fSize; } +// +// protected: +// size_t fSize; +// void* fBuffer; +//}; +// +// +//static int +//strprintf(string &str, const char * format, ...) +//{ +// va_list argptr; +// +// char strfix[128]; +// +// va_start(argptr, format); +// int ret = vsnprintf(strfix, 128, format, argptr); +// va_end(argptr); +// +// if (ret == -1) { +// MemBlock strbuf; +// strbuf.SetSize(128); +// while (ret == -1) { +// strbuf.SetSize(strbuf.Size() * 2); +// va_start(argptr, format); +// ret = vsnprintf(strbuf.Access(), strbuf.Size(), format, argptr); +// va_end(argptr); +// } +// str.assign(strbuf.Access()); +// } else if (ret >= 128) { +// MemBlock strbuf; +// strbuf.SetSize(ret + 1); +// va_start(argptr, format); +// ret = vsnprintf(strbuf.Access(), ret + 1, format, argptr); +// va_end(argptr); +// str.assign(strbuf.Access()); +// } else { +// str.assign(strfix); +// } +// +// return ret; +//} + + +static double +valtod(const char* exp, const char** end) { - // http://en.wikipedia.org/wiki/SI_prefix + // http://en.wikipedia.org/wiki/SI_prefix - char *endptr; - double temp = strtod(exp, &endptr); - if (endptr == exp || !*endptr) - { - if (end) *end = endptr; - return temp; - } - if (end) *end = endptr + 1; - switch(*endptr) - { -/* case 'Y': // yotta - return temp * 1.E24; - break; - case 'Z': // zetta - return temp * 1.E21; - break; - case 'E': // exa, incompatible with exponent! - return temp * 1.E18; - break;*/ - case 'P': // peta - return temp * 1.E15; - break; - case 'T': // tera - return temp * 1.E12; - break; - case 'G': // giga - return temp * 1.E9; - break; - case 'M': // mega - return temp * 1.E6; - break; - case 'k': // kilo - return temp * 1.E3; - break; - case 'h': // hecto - return temp * 1.E2; - break; - case 'd': - if (endptr[1] == 'a') - { - if (end) *end = endptr + 2; - return temp * 1.E1; // deca - } - else - return temp * 1.E-1; // deci - break; - case 'c': // centi - return temp * 1.E-2; - break; - case 'm': // milli - return temp * 1.E-3; - break; - case 'u': // micro - return temp * 1.E-6; - break; - case 'n': // nano - return temp * 1.E-9; - break; - case 'p': // pico - return temp * 1.E-12; - break; - case 'f': // femto - return temp * 1.E-15; - break; - case 'a': // atto - return temp * 1.E-18; - break; - case 'z': // zepto - return temp * 1.E-21; - break; - case 'y': // yocto - return temp * 1.E-24; - break; - } - if (end) *end = endptr; - return temp; -} - -double Expression::exptod(const char *str, const char **end) -{ - Expression exp; - - const char *evalEnd = str + strlen(str); - double temp = exp.Eval(str, evalEnd); - - const char *err = exp.Error(); - if (end) *end = err ? err : evalEnd; - - return temp; -} - -string Expression::dtostr(const double value, const unsigned int precision, const char mode) -{ - if (value == 0.0) - return "0"; - string str; - char prefix[2]; - prefix[0] = 0; - prefix[1] = 0; - if (mode == 1) // exp3 - { - double exp = floor(log10(fabs(value)) / 3.) * 3; - string format; - strprintf(format, "%%.%dGE%%ld", precision); - strprintf(str, format.c_str(), value / pow(10., exp), exp); - } - else if (mode == 2) // prefix - { - double exp = floor(log10(fabs(value)) / 3.) * 3; - string format; - strprintf(format, "%%.%dG", precision); - strprintf(str, format.c_str(), value / pow(10., exp)); - switch(int(exp)) - { - case 24: // yotta - prefix[0] = 'Y'; - break; - case 21: // zetta - prefix[0] = 'Z'; - break; - case 18: // exa - prefix[0] = 'E'; - break; - case 15: // peta - prefix[0] = 'P'; - break; - case 12: // tera - prefix[0] = 'T'; - break; - case 9: // giga - prefix[0] = 'G'; - break; - case 6: // mega - prefix[0] = 'M'; - break; - case 3: // kilo - prefix[0] = 'k'; - break; - case -3: // milli - prefix[0] = 'm'; - break; - case -6: // micro - prefix[0] = 'u'; - break; - case -9: // nano - prefix[0] = 'n'; - break; - case -12: // pico - prefix[0] = 'p'; - break; - case -15: // femto - prefix[0] = 'f'; - break; - case -18: // atto - prefix[0] = 'a'; - break; - case -21: // zepto - prefix[0] = 'z'; - break; - case -24: // yocto - prefix[0] = 'y'; - break; - default: - if (exp) - { - strprintf(format, "%%.%dGE%%ld", precision); - strprintf(str, format.c_str(), value / pow(10., exp), exp); - } - else - { - strprintf(format, "%%.%dG", precision); - strprintf(str, format.c_str(), value); - } - break; - } - } - else // exp - { - string format; - strprintf(format, "%%.%dG", precision); - strprintf(str, format.c_str(), value); - } - return string(str) + prefix; -} - -template -class MemBlock -{ -public: - MemBlock() - : m_bSize(0), - m_buf(0){} - - MemBlock(const MemBlock& src) - : m_bSize(0), - m_buf(0) - { - SetSize(src.m_bSize); - memcpy(m_buf, src.m_buf, src.m_bSize); - } - - MemBlock& operator=(const MemBlock& src) - { - if (this != &src) - { - SetSize(src.m_bSize); - memcpy(m_buf, src.m_buf, src.m_bSize); - } - return (*this); - } - - ~MemBlock () - { - if (m_buf) - { - free(m_buf); - } - } - - void SetSize(const size_t size) - { - size_t oldsize = Size(); - if (oldsize != size) - { - if (!m_buf && size) - { - m_buf = malloc(size); - if (!m_buf) - throw "Out of memory"; - } - if (m_buf && size) - { - void *newBuf = realloc(m_buf, size); - if (newBuf) - m_buf = newBuf; - else - throw "Out of memory"; - } - if (m_buf && !size) - { - free(m_buf); - m_buf = 0; - } - m_bSize = size; - } - } - void * Buffer() const { return m_buf; } - T * Access() const { return (T *)m_buf; } - T & operator[](size_t i) const - { - return Access()[i]; - } - size_t Size() const { return m_bSize; } - -protected: - size_t m_bSize; - void *m_buf; -}; - -int Expression::strprintf(string &str, const char * format, ...) -{ - va_list argptr; - - char strfix[128]; - - va_start(argptr, format); - int ret = vsnprintf(strfix, 128, format, argptr); - va_end(argptr); - - if (ret == -1) - { - MemBlock strbuf; - strbuf.SetSize(128); - while (ret == -1) - { - strbuf.SetSize(strbuf.Size() * 2); - va_start(argptr, format); - ret = vsnprintf(strbuf.Access(), strbuf.Size(), format, argptr); - va_end(argptr); - } - str.assign(strbuf.Access()); - } - else if (ret >= 128) - { - MemBlock strbuf; - strbuf.SetSize(ret + 1); - va_start(argptr, format); - ret = vsnprintf(strbuf.Access(), ret + 1, format, argptr); - va_end(argptr); - str.assign(strbuf.Access()); - } - else - { - str.assign(strfix); - } - - return ret; -} - -Expression::Expression(): - m_aglf(1.), - m_errorPtr(NULL), - m_trig(false) -{ - m_functionNames.push_back("sin("); // 0 - m_functionTypes.push_back(1); - m_functionNames.push_back("asin("); // 1 - m_functionTypes.push_back(2); - m_functionNames.push_back("cos("); // 2 - m_functionTypes.push_back(1); - m_functionNames.push_back("acos("); // 3 - m_functionTypes.push_back(2); - m_functionNames.push_back("tan("); // 4 - m_functionTypes.push_back(1); - m_functionNames.push_back("atan("); // 5 - m_functionTypes.push_back(2); - m_functionNames.push_back("ln("); // 6 - m_functionTypes.push_back(0); - m_functionNames.push_back("lg("); // 7 - m_functionTypes.push_back(0); - m_functionNames.push_back("sqrt("); // 8 - m_functionTypes.push_back(0); - m_functionNames.push_back("("); // 9 - m_functionTypes.push_back(0); - - SetConstant("e", M_E); - SetConstant("pi", M_PI); -} - -double Expression::func(const double x, const size_t number) const -{ - switch (number) - { - case 0: - return sin(x); - case 1: - return asin(x); - case 2: - return cos(x); - case 3: - return acos(x); - case 4: - return tan(x); - case 5: - return atan(x); - case 6: - return log(x); - case 7: - return log10(x); - case 8: - return sqrt(x); - default: - return x; - } -} - -void Expression::SetAglf(const double value) -{ - m_aglf = value; -} - -bool Expression::SetConstant(const char *name, const double value) -{ - size_t i; - for (i = 0; name[i]; i++) - { - if (!isalnum(name[i])) - { - throw "Illegal character in constant name"; - } - } - for (i = 0; i < m_constantNames.size(); i++) - { - if (!strcmp(name, m_constantNames[i].c_str())) - { - m_constantValues[i] = value; - return true; - } - } - m_constantNames.push_back(name); - m_constantValues.push_back(value); - return false; -} - -double Expression::Eval(const char *exp) -{ - const char *evalEnd = exp + strlen(exp); - return Eval(exp, evalEnd); -} - -double Expression::Eval(const char *begin, const char *end, const bool allowWhiteSpaces) -{ - const char *curptr = begin; - int state = 1; - double operand; - double sum = 0.; - double prod = 0.0; - double power = 0.0; - - if (begin[0] == 0) - { - m_errorPtr = begin; - return 0.; - } - - if (m_errorPtr) - { - return 0.; - } - - for (;;) - { - const char *operandEnd; - bool minusBeforeOperand = false; - bool numberOperand = true; - - if (allowWhiteSpaces) - { - // TODO: Remove white spaces + char *endptr; + double temp = strtod(exp, &endptr); + if (endptr == exp || !*endptr) { + if (end) + *end = endptr; + return temp; } - if (curptr[0] == '-') - minusBeforeOperand = true; + if (end) + *end = endptr + 1; - operand = valtod(curptr, &operandEnd); + switch (*endptr) { + /* case 'Y': // yotta + return temp * 1.E24; + case 'Z': // zetta + return temp * 1.E21; + case 'E': // exa, incompatible with exponent! + return temp * 1.E18;*/ + case 'P': // peta + return temp * 1.E15; + case 'T': // tera + return temp * 1.E12; + case 'G': // giga + return temp * 1.E9; + case 'M': // mega + return temp * 1.E6; + case 'k': // kilo + return temp * 1.E3; + case 'h': // hecto + return temp * 1.E2; + case 'd': + if (endptr[1] == 'a') { + if (end) + *end = endptr + 2; + return temp * 1.E1; // deca + } else + return temp * 1.E-1; // deci + case 'c': // centi + return temp * 1.E-2; + case 'm': // milli + return temp * 1.E-3; + case 'u': // micro + return temp * 1.E-6; + case 'n': // nano + return temp * 1.E-9; + case 'p': // pico + return temp * 1.E-12; + case 'f': // femto + return temp * 1.E-15; + case 'a': // atto + return temp * 1.E-18; + case 'z': // zepto + return temp * 1.E-21; + case 'y': // yocto + return temp * 1.E-24; + } + if (end) + *end = endptr; - if (operandEnd == curptr) - { // operand not a number - const char *operandStart = curptr; - double operandSign = 1.; + return temp; +} - numberOperand = false; +// NOTE: commented because unused - if (curptr[0] == '+') - { - ++operandStart; - } - else if (curptr[0] == '-') - { - ++operandStart; - operandSign = -1.; - } +//static double +//exptod(const char* str, const char** end) +//{ +// Expression exp; +// +// const char* evalEnd = str + strlen(str); +// double temp = exp.Evaluate(str, evalEnd); +// +// const char* err = exp.Error(); +// if (end) +// *end = err ? err : evalEnd; +// +// return temp; +//} +// +// +//static string +//dtostr(const double value, const unsigned int precision, const char mode) +//{ +// if (value == 0.0) +// return "0"; +// +// string str; +// char prefix[2]; +// prefix[0] = 0; +// prefix[1] = 0; +// +// if (mode == 1) { +// // exp3 +// double exp = floor(log10(fabs(value)) / 3.) * 3; +// string format; +// strprintf(format, "%%.%dGE%%ld", precision); +// strprintf(str, format.c_str(), value / pow(10., exp), exp); +// } else if (mode == 2) { +// // prefix +// double exp = floor(log10(fabs(value)) / 3.) * 3; +// string format; +// strprintf(format, "%%.%dG", precision); +// strprintf(str, format.c_str(), value / pow(10., exp)); +// switch (int(exp)) { +// case 24: // yotta +// prefix[0] = 'Y'; +// break; +// case 21: // zetta +// prefix[0] = 'Z'; +// break; +// case 18: // exa +// prefix[0] = 'E'; +// break; +// case 15: // peta +// prefix[0] = 'P'; +// break; +// case 12: // tera +// prefix[0] = 'T'; +// break; +// case 9: // giga +// prefix[0] = 'G'; +// break; +// case 6: // mega +// prefix[0] = 'M'; +// break; +// case 3: // kilo +// prefix[0] = 'k'; +// break; +// case -3: // milli +// prefix[0] = 'm'; +// break; +// case -6: // micro +// prefix[0] = 'u'; +// break; +// case -9: // nano +// prefix[0] = 'n'; +// break; +// case -12: // pico +// prefix[0] = 'p'; +// break; +// case -15: // femto +// prefix[0] = 'f'; +// break; +// case -18: // atto +// prefix[0] = 'a'; +// break; +// case -21: // zepto +// prefix[0] = 'z'; +// break; +// case -24: // yocto +// prefix[0] = 'y'; +// break; +// default: +// if (exp) { +// strprintf(format, "%%.%dGE%%ld", precision); +// strprintf(str, format.c_str(), value / pow(10., exp), exp); +// } else { +// strprintf(format, "%%.%dG", precision); +// strprintf(str, format.c_str(), value); +// } +// break; +// } +// } else { +// // exp +// string format; +// strprintf(format, "%%.%dG", precision); +// strprintf(str, format.c_str(), value); +// } +// +// return string(str) + prefix; +//} - // Iterate through functions - size_t i; - for (i = 0; i < m_functionNames.size(); i++) - { - if (!strncmp(operandStart, m_functionNames[i].c_str(), m_functionNames[i].size())) - { - const char *functionArg = operandStart + m_functionNames[i].size(); - const char *chptr = functionArg - 1; - const char *prptr = functionArg - 1; - if (m_functionTypes[i]) - m_trig = true; +// #pragma mark - - // Find closing paranthesis - while (prptr) - { - chptr = strchr(chptr + 1, ')'); - prptr = strchr(prptr + 1, '('); - if (prptr > chptr) - break; - } - if (chptr) - { // Closing paranthesis - if (m_functionTypes[i] == 1) // Trig - { - operand = operandSign * func(m_aglf * Eval(functionArg, chptr), i); - if (fabs(operand) < NOLLF) - operand = 0; +Expression::Expression() + : fAglf(1.), + fErrorPtr(NULL), + fTrig(false) +{ + // NOTE: these seem to be hard coded anyways... + fFunctionNames.push_back("sin("); // 0 + fFunctionTypes.push_back(1); + fFunctionNames.push_back("asin("); // 1 + fFunctionTypes.push_back(2); + fFunctionNames.push_back("cos("); // 2 + fFunctionTypes.push_back(1); + fFunctionNames.push_back("acos("); // 3 + fFunctionTypes.push_back(2); + fFunctionNames.push_back("tan("); // 4 + fFunctionTypes.push_back(1); + fFunctionNames.push_back("atan("); // 5 + fFunctionTypes.push_back(2); + fFunctionNames.push_back("ln("); // 6 + fFunctionTypes.push_back(0); + fFunctionNames.push_back("lg("); // 7 + fFunctionTypes.push_back(0); + fFunctionNames.push_back("sqrt("); // 8 + fFunctionTypes.push_back(0); + fFunctionNames.push_back("("); // 9 + fFunctionTypes.push_back(0); + + SetConstant("e", M_E); + SetConstant("pi", M_PI); +} + + +void +Expression::SetAglf(const double value) +{ + fAglf = value; +} + + +bool +Expression::SetConstant(const char* name, const double value) +{ + for (size_t i = 0; name[i]; i++) { + if (!isalnum(name[i])) { + throw "Illegal character in constant name"; + } + } + for (size_t i = 0; i < fConstantNames.size(); i++) { + if (!strcmp(name, fConstantNames[i].c_str())) { + fConstantValues[i] = value; + return true; + } + } + + fConstantNames.push_back(name); + fConstantValues.push_back(value); + + return false; +} + + +double +Expression::Evaluate(const char* exp) +{ + const char* evalEnd = exp + strlen(exp); + return Evaluate(exp, evalEnd); +} + + +double +Expression::Evaluate(const char* begin, const char* end, const bool allowWhiteSpaces) +{ + const char* curptr = begin; + int state = 1; + double operand; + double sum = 0.; + double prod = 0.0; + double power = 0.0; + + if (begin[0] == 0) { + fErrorPtr = begin; + return 0.; + } + + if (fErrorPtr) { + return 0.; + } + + for (;;) { + const char *operandEnd; + bool minusBeforeOperand = false; + bool numberOperand = true; + + if (allowWhiteSpaces) { + while (curptr < end && isspace(curptr[0])) + curptr++; + } + + if (curptr[0] == '-') + minusBeforeOperand = true; + + operand = valtod(curptr, &operandEnd); + + if (operandEnd == curptr) { + // operand not a number + const char *operandStart = curptr; + double operandSign = 1.; + + numberOperand = false; + + if (curptr[0] == '+') { + ++operandStart; + } else if (curptr[0] == '-') { + ++operandStart; + operandSign = -1.; } - else if (m_functionTypes[i] == 2) // Inv trig - { - operand = operandSign / m_aglf * func(Eval(functionArg, chptr), i); - } - else // Normal - { - operand = operandSign * func(Eval(functionArg, chptr), i); - } - operandEnd = chptr + 1; - } - else - { // No closing paranthesis - if (m_functionTypes[i] == 1) - { - operand = operandSign * func(m_aglf * Eval(functionArg, end), i); - if (fabs(operand) < NOLLF) - operand = 0; - } - else if (m_functionTypes[i] == 2) - { - operand = operandSign / m_aglf * func(Eval(functionArg, end), i); - } - else - { - operand = operandSign * func(Eval(functionArg, end), i); - } - operandEnd = end; - } - if (m_errorPtr) - { - return 0.; - } + // Iterate through functions + size_t i; + for (i = 0; i < fFunctionNames.size(); i++) { + if (!strncmp(operandStart, fFunctionNames[i].c_str(), fFunctionNames[i].size())) { + const char *functionArg = operandStart + fFunctionNames[i].size(); + const char *chptr = functionArg - 1; + const char *prptr = functionArg - 1; + + if (fFunctionTypes[i]) + fTrig = true; + + // Find closing paranthesis + while (prptr) { + chptr = strchr(chptr + 1, ')'); + prptr = strchr(prptr + 1, '('); + if (prptr > chptr) + break; + } - break; + if (chptr) { + // Closing paranthesis + if (fFunctionTypes[i] == 1) { + // Trig + operand = operandSign * _ApplyFunction(fAglf * Evaluate(functionArg, chptr), i); + if (fabs(operand) < NOLLF) + operand = 0; + } else if (fFunctionTypes[i] == 2) { + // Inv trig + operand = operandSign / fAglf * _ApplyFunction(Evaluate(functionArg, chptr), i); + } else { + // Normal + operand = operandSign * _ApplyFunction(Evaluate(functionArg, chptr), i); + } + operandEnd = chptr + 1; + } else { + // No closing paranthesis + if (fFunctionTypes[i] == 1) { + operand = operandSign * _ApplyFunction(fAglf * Evaluate(functionArg, end), i); + if (fabs(operand) < NOLLF) + operand = 0; + } else if (fFunctionTypes[i] == 2) { + operand = operandSign / fAglf * _ApplyFunction(Evaluate(functionArg, end), i); + } else { + operand = operandSign * _ApplyFunction(Evaluate(functionArg, end), i); + } + operandEnd = end; + } + + if (fErrorPtr) { + return 0.; + } + + break; + } + } + + // Iterate through constants + if (i == fFunctionNames.size()) { + // Only search if no function found + for (i = 0; i < fConstantNames.size(); i++) { + if (!strncmp(operandStart, fConstantNames[i].c_str(), fConstantNames[i].size()) && !isalnum(operandStart[fConstantNames[i].size()])) { + operandEnd = operandStart + fConstantNames[i].size(); + operand = operandSign * fConstantValues[i]; + break; + } + } + } } - } - // Iterate through constants - if (i == m_functionNames.size()) // Only search if no function found - for (i = 0; i < m_constantNames.size(); i++) - { - if (!strncmp(operandStart, m_constantNames[i].c_str(), m_constantNames[i].size()) && !isalnum(operandStart[m_constantNames[i].size()])) - { - operandEnd = operandStart + m_constantNames[i].size(); - operand = operandSign * m_constantValues[i]; - break; + if (operandEnd > end) { + fErrorPtr = end; + return 0.; + } + + // Calculate expression in correct order + + // state == 1 => term => sum + operand + // state == 2 => product => sum + prod * operand + // state == 3 => quotient => sum + prod / operand + // state == 4 => plus & power => sum + power ^ operand + // state == 5 => minus & power => sum - power ^ operand + // state == 6 => product & power => sum + prod * power ^ operand + // state == 7 => quotient & power => sum + prod / power ^ operand + + if (curptr != operandEnd) { + // number? + switch (state) { + case 1: // term + if (operandEnd == end) { + return sum + operand; + } + switch (operandEnd[0]) { + // Check next + case '+': + case '-': + curptr = operandEnd; + sum = sum + operand; + break; + case '*': + curptr = operandEnd + 1; + prod = operand; + state = 2; + break; + case '/': + curptr = operandEnd + 1; + prod = operand; + state = 3; + break; + case '^': + curptr = operandEnd + 1; + power = operand; + if (minusBeforeOperand) { + power = power * -1.; + state = 5; + } else { + state = 4; + } + break; + default: + if (numberOperand && isalpha(operandEnd[0])) { + // Assume multiplication of function/constant without * + curptr = operandEnd; + prod = operand; + state = 2; + } else { + fErrorPtr = operandEnd; + return 0.; + } + } + break; + + case 2: // product + if (operandEnd == end) { + return sum + prod * operand; + } + switch (operandEnd[0]) { + // Check next + case '+': + case '-': + curptr = operandEnd; + sum = sum + prod * operand; + state = 1; + break; + case '*': + curptr = operandEnd + 1; + prod = prod * operand; + break; + case '/': + curptr = operandEnd + 1; + prod = prod * operand; + state = 3; + break; + case '^': + curptr = operandEnd + 1; + power = operand; + state = 6; + break; + default: + fErrorPtr = operandEnd; + return 0.; + } + break; + + case 3: // quotient + if (operandEnd == end) { + return sum + prod / operand; + } + switch (operandEnd[0]) { + // Check next + case '+': + case '-': + curptr = operandEnd; + sum = sum + prod / operand; + state = 1; + break; + case '*': + curptr = operandEnd + 1; + prod = prod / operand; + state = 2; + break; + case '/': + curptr = operandEnd + 1; + prod = prod / operand; + break; + case '^': + curptr = operandEnd + 1; + power = operand; + state = 7; + break; + default: + fErrorPtr = operandEnd; + return 0.; + } + break; + + case 4: // plus&power + if (operandEnd == end) { + return sum + pow(power, operand); + } + switch (operandEnd[0]) { + // Check next + case '+': + case '-': + curptr = operandEnd; + sum = sum + pow(power, operand); + state = 1; + break; + case '*': + curptr = operandEnd + 1; + prod = pow(power, operand); + state = 2; + break; + case '/': + curptr = operandEnd + 1; + prod = pow(power, operand); + state = 3; + break; + case '^': + curptr = operandEnd + 1; + power = pow(power, operand); + break; + default: + fErrorPtr = operandEnd; + return 0.; + } + break; + + case 5: // minus&power + if (operandEnd == end) { + return sum - pow(power, operand); + } + switch (operandEnd[0]) { + // Check next + case '+': + case '-': + curptr = operandEnd; + sum = sum - pow(power, operand); + state = 1; + break; + case '*': + curptr = operandEnd + 1; + prod = pow(power, operand); + state = 2; + break; + case '/': + curptr = operandEnd + 1; + prod = pow(power, operand); + state = 3; + break; + case '^': + curptr = operandEnd + 1; + power = pow(power, operand); + break; + default: + fErrorPtr = operandEnd; + return 0.; + } + break; + + case 6: // product&power + if (operandEnd == end) { + return sum + prod * pow(power, operand); + } + switch (operandEnd[0]) { + // Check next + case '+': + case '-': + curptr = operandEnd; + sum = sum + prod * pow(power, operand); + state = 1; + break; + case '*': + curptr = operandEnd + 1; + prod = prod * pow(power, operand); + state = 2; + break; + case '/': + curptr = operandEnd + 1; + prod = prod * pow(power, operand); + state = 3; + break; + case '^': + curptr = operandEnd + 1; + power = pow(power, operand); + break; + default: + fErrorPtr = operandEnd; + return 0.; + } + break; + + case 7: // quotient&power + if (operandEnd == end) { + return sum + prod / pow(power, operand); + } + switch (operandEnd[0]) { + // Check next + case '+': + case '-': + curptr = operandEnd; + sum = sum + prod / pow(power, operand); + state = 1; + break; + case '*': + curptr = operandEnd + 1; + prod = prod / pow(power, operand); + state = 2; + break; + case '/': + curptr = operandEnd + 1; + prod = prod / pow(power, operand); + state = 3; + break; + case '^': + curptr = operandEnd + 1; + power = pow(power, operand); + break; + default: + fErrorPtr = operandEnd; + return 0.; + } + break; + + default: + fErrorPtr = operandEnd; + return 0.; + } + } else { + fErrorPtr = curptr; + return 0.; } - } } - - if (operandEnd > end) - { - m_errorPtr = end; - return 0.; - } - - // Calculate expression in correct order - - // state == 1 => term => sum + operand - // state == 2 => product => sum + prod * operand - // state == 3 => quotient => sum + prod / operand - // state == 4 => plus & power => sum + power ^ operand - // state == 5 => minus & power => sum - power ^ operand - // state == 6 => product & power => sum + prod * power ^ operand - // state == 7 => quotient & power => sum + prod / power ^ operand - - if (curptr != operandEnd) // number? - { - switch (state) - { - case 1: // term - if (operandEnd == end) - { - return sum + operand; - } - switch (operandEnd[0]) - { // Check next - case '+': - case '-': - curptr = operandEnd; - sum = sum + operand; - break; - case '*': - curptr = operandEnd + 1; - prod = operand; - state = 2; - break; - case '/': - curptr = operandEnd + 1; - prod = operand; - state = 3; - break; - case '^': - curptr = operandEnd + 1; - power = operand; - if (minusBeforeOperand) - { - power = power * -1.; - state = 5; - } - else - { - state = 4; - } - break; - default: - if (numberOperand && isalpha(operandEnd[0])) - { // Assume multiplication of function/constant without * - curptr = operandEnd; - prod = operand; - state = 2; - } - else - { - m_errorPtr = operandEnd; - return 0.; - } - } - break; - case 2: // product - if (operandEnd == end) - { - return sum + prod * operand; - } - switch (operandEnd[0]) - { // Check next - case '+': - case '-': - curptr = operandEnd; - sum = sum + prod * operand; - state = 1; - break; - case '*': - curptr = operandEnd + 1; - prod = prod * operand; - break; - case '/': - curptr = operandEnd + 1; - prod = prod * operand; - state = 3; - break; - case '^': - curptr = operandEnd + 1; - power = operand; - state = 6; - break; - default: - m_errorPtr = operandEnd; - return 0.; - } - break; - case 3: // quotient - if (operandEnd == end) - { - return sum + prod / operand; - } - switch (operandEnd[0]) - { // Check next - case '+': - case '-': - curptr = operandEnd; - sum = sum + prod / operand; - state = 1; - break; - case '*': - curptr = operandEnd + 1; - prod = prod / operand; - state = 2; - break; - case '/': - curptr = operandEnd + 1; - prod = prod / operand; - break; - case '^': - curptr = operandEnd + 1; - power = operand; - state = 7; - break; - default: - m_errorPtr = operandEnd; - return 0.; - } - break; - case 4: // plus&power - if (operandEnd == end) - { - return sum + pow(power, operand); - } - switch (operandEnd[0]) - { // Check next - case '+': - case '-': - curptr = operandEnd; - sum = sum + pow(power, operand); - state = 1; - break; - case '*': - curptr = operandEnd + 1; - prod = pow(power, operand); - state = 2; - break; - case '/': - curptr = operandEnd + 1; - prod = pow(power, operand); - state = 3; - break; - case '^': - curptr = operandEnd + 1; - power = pow(power, operand); - break; - default: - m_errorPtr = operandEnd; - return 0.; - } - break; - case 5: // minus&power - if (operandEnd == end) - { - return sum - pow(power, operand); - } - switch (operandEnd[0]) - { // Check next - case '+': - case '-': - curptr = operandEnd; - sum = sum - pow(power, operand); - state = 1; - break; - case '*': - curptr = operandEnd + 1; - prod = pow(power, operand); - state = 2; - break; - case '/': - curptr = operandEnd + 1; - prod = pow(power, operand); - state = 3; - break; - case '^': - curptr = operandEnd + 1; - power = pow(power, operand); - break; - default: - m_errorPtr = operandEnd; - return 0.; - } - break; - case 6: // product&power - if (operandEnd == end) - { - return sum + prod * pow(power, operand); - } - switch (operandEnd[0]) - { // Check next - case '+': - case '-': - curptr = operandEnd; - sum = sum + prod * pow(power, operand); - state = 1; - break; - case '*': - curptr = operandEnd + 1; - prod = prod * pow(power, operand); - state = 2; - break; - case '/': - curptr = operandEnd + 1; - prod = prod * pow(power, operand); - state = 3; - break; - case '^': - curptr = operandEnd + 1; - power = pow(power, operand); - break; - default: - m_errorPtr = operandEnd; - return 0.; - } - break; - case 7: // quotient&power - if (operandEnd == end) - { - return sum + prod / pow(power, operand); - } - switch (operandEnd[0]) - { // Check next - case '+': - case '-': - curptr = operandEnd; - sum = sum + prod / pow(power, operand); - state = 1; - break; - case '*': - curptr = operandEnd + 1; - prod = prod / pow(power, operand); - state = 2; - break; - case '/': - curptr = operandEnd + 1; - prod = prod / pow(power, operand); - state = 3; - break; - case '^': - curptr = operandEnd + 1; - power = pow(power, operand); - break; - default: - m_errorPtr = operandEnd; - return 0.; - } - break; - default: - m_errorPtr = operandEnd; - return 0.; - } - } - else - { - m_errorPtr = curptr; - return 0.; - } - } } -const char *Expression::Error() + +const char* +Expression::Error() { - const char *retval = m_errorPtr; - m_errorPtr = NULL; - m_trig = false; - return retval; + const char *retval = fErrorPtr; + fErrorPtr = NULL; + fTrig = false; + return retval; } + +// #pragma mark - + + +double +Expression::_ApplyFunction(const double x, const size_t number) const +{ + switch (number) { + case 0: + return sin(x); + case 1: + return asin(x); + case 2: + return cos(x); + case 3: + return acos(x); + case 4: + return tan(x); + case 5: + return atan(x); + case 6: + return log(x); + case 7: + return log10(x); + case 8: + return sqrt(x); + default: + return x; + } +} diff --git a/src/apps/deskcalc/Parser.h b/src/apps/deskcalc/Parser.h index d9d5d7a526..c63557846c 100644 --- a/src/apps/deskcalc/Parser.h +++ b/src/apps/deskcalc/Parser.h @@ -40,31 +40,30 @@ class Expression { public: - static double valtod(const char *exp, const char **end); - static double exptod(const char *exp, const char **end); - static std::string dtostr(const double value, const unsigned int precision, const char mode); // 0 => exp, 1 => exp3, 2 => SI - static int strprintf(std::string &str, const char * format, ...); + Expression(); - Expression(); + void SetAglf(const double value); + bool SetConstant(const char* name, + const double value); - void SetAglf(const double value); - bool SetConstant(const char *name, const double value); - - double Eval(const char *exp); - double Eval(const char *begin, const char *end, const bool allowWhiteSpaces = false); - const char *Error(); + double Evaluate(const char* exp); + double Evaluate(const char* begin, const char* end, + const bool allowWhiteSpaces = false); + const char* Error(); private: - double m_aglf; - const char *m_errorPtr; - bool m_trig; + double _ApplyFunction(const double x, + const size_t number) const; - double func(const double x, const size_t number) const; - std::vector m_functionNames; - std::vector m_functionTypes; + double fAglf; + const char* fErrorPtr; + bool fTrig; - std::vector m_constantNames; - std::vector m_constantValues; + std::vector fFunctionNames; + std::vector fFunctionTypes; + + std::vector fConstantNames; + std::vector fConstantValues; }; #endif // PARSER_H