From 665c794f1de47714cdb5d6cc7813a5569afaecdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Wed, 21 Apr 2010 17:20:29 +0000 Subject: [PATCH] Patch by Wim: The resulting expression string is now fit to the current width of the window. Insignificant digits are truncated from the end. DeskCalc may also switch to scientific notation if there is not enough room left. Thanks a lot! Fixes ticket #5203. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36402 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/deskcalc/CalcView.cpp | 2 +- src/apps/deskcalc/ExpressionTextView.cpp | 173 ++++++++++++++++++++++- src/apps/deskcalc/ExpressionTextView.h | 5 + 3 files changed, 173 insertions(+), 7 deletions(-) diff --git a/src/apps/deskcalc/CalcView.cpp b/src/apps/deskcalc/CalcView.cpp index c23f7a5aa5..7da8893f6a 100644 --- a/src/apps/deskcalc/CalcView.cpp +++ b/src/apps/deskcalc/CalcView.cpp @@ -917,7 +917,7 @@ CalcView::Evaluate() } // render new result to display - fExpressionTextView->SetExpression(value.String()); + fExpressionTextView->SetValue(value.String()); } diff --git a/src/apps/deskcalc/ExpressionTextView.cpp b/src/apps/deskcalc/ExpressionTextView.cpp index da3c6a5a4a..1f992adfd0 100644 --- a/src/apps/deskcalc/ExpressionTextView.cpp +++ b/src/apps/deskcalc/ExpressionTextView.cpp @@ -30,7 +30,9 @@ ExpressionTextView::ExpressionTextView(BRect frame, CalcView* calcView) fKeypadLabels(""), fPreviousExpressions(20), fHistoryPos(0), - fCurrentExpression("") + fCurrentExpression(""), + fCurrentValue(""), + fChangesApplied(false) { SetStylable(false); SetDoesUndo(true); @@ -64,7 +66,7 @@ ExpressionTextView::MakeFocus(bool focused) void ExpressionTextView::KeyDown(const char* bytes, int32 numBytes) { - // handle expression history + // Handle expression history if (bytes[0] == B_UP_ARROW) { PreviousExpression(); return; @@ -75,22 +77,30 @@ ExpressionTextView::KeyDown(const char* bytes, int32 numBytes) } BString current = Text(); - // handle in InputTextView, except B_TAB + // Handle in InputTextView, except B_TAB if (bytes[0] == '=') ApplyChanges(); else if (bytes[0] != B_TAB) InputTextView::KeyDown(bytes, numBytes); - // pass on to CalcView if this was a label on a key + // Pass on to CalcView if this was a label on a key if (fKeypadLabels.FindFirst(bytes[0]) >= 0) fCalcView->FlashKey(bytes, numBytes); else if (bytes[0] == B_BACKSPACE) fCalcView->FlashKey("BS", 2); - // as soon as something is typed, we are at the - // end of the expression history + // As soon as something is typed, we are at the end of the expression + // history. if (current != Text()) fHistoryPos = fPreviousExpressions.CountItems(); + + // If changes where not applied the value has become a new expression + // note that even if only the left or right arrow keys are pressed the + // fCurrentValue string will be cleared. + if (!fChangesApplied) + fCurrentValue.SetTo(""); + else + fChangesApplied = false; } @@ -117,6 +127,17 @@ ExpressionTextView::GetDragParameters(BMessage* dragMessage, } +void +ExpressionTextView::SetTextRect(BRect rect) +{ + InputTextView::SetTextRect(rect); + + int32 count = fPreviousExpressions.CountItems(); + if (fHistoryPos == count && fCurrentValue.CountChars() > 0) + SetValue(fCurrentValue.String()); +} + + // #pragma mark - @@ -133,6 +154,7 @@ ExpressionTextView::ApplyChanges() AddExpressionToHistory(Text()); fCalcView->FlashKey("=", 1); fCalcView->Evaluate(); + fChangesApplied = true; } @@ -155,6 +177,145 @@ ExpressionTextView::SetExpression(const char* expression) } +void +ExpressionTextView::SetValue(const char* value) +{ + // copy the value string so we can modify it + BString val(value); + + // save the value + fCurrentValue = val; + + // calculate the width of the string + BFont font; + uint32 mode = B_FONT_ALL; + GetFontAndColor(&font, &mode); + float stringWidth = font.StringWidth(val); + + // make the string shorter if it does not fit in the view + float viewWidth = Frame().Width(); + if (val.CountChars() > 3 && stringWidth > viewWidth) { + + // get the position of the first digit + int32 firstDigit = 0; + if (val[0] == '-') + firstDigit++; + + // calculate the value of the exponent + int32 exponent = 0; + int32 offset = val.FindFirst('.'); + if (offset == B_ERROR) { + exponent = val.CountChars() - 1 - firstDigit; + val.Insert('.', 1, firstDigit + 1); + } else { + if (offset == firstDigit + 1) { + // if the value is 0.01 or larger then scientific notation + // won't shorten the string + if (val[firstDigit] != '0' || val[firstDigit+2] != '0' + || val[firstDigit+3] != '0') { + exponent = 0; + } else { + // remove the period + val.Remove(offset, 1); + + // check for negative exponent value + exponent = 0; + while (val[firstDigit] == '0') { + val.Remove(firstDigit, 1); + exponent--; + } + + //add the period + val.Insert('.', 1, firstDigit + 1); + } + } else { + // if the period + 1 digit fits in the view scientific notation + // won't shorten the string + BString temp = val; + temp.Truncate(offset + 2); + stringWidth = font.StringWidth(temp); + if (stringWidth < viewWidth) + exponent = 0; + else { + // move the period + val.Remove(offset, 1); + val.Insert('.', 1, firstDigit + 1); + + exponent = offset - (firstDigit + 1); + } + } + } + + // add the exponent + offset = val.CountChars() - 1; + if (exponent != 0) + val << "E" << exponent; + + // reduce the number of digits until the string fits or can not be + // made any shorter + stringWidth = font.StringWidth(val); + char lastRemovedDigit = '0'; + while (offset > firstDigit && stringWidth > viewWidth) { + if (val[offset] != '.') + lastRemovedDigit = val[offset]; + val.Remove(offset--, 1); + stringWidth = font.StringWidth(val); + } + + // there is no need to keep the period if no digits follow + if (val[offset] == '.') { + val.Remove(offset, 1); + offset--; + } + + // take care of proper rounding of the result + int digit = (int)lastRemovedDigit - 48; // ascii to int + if (digit >= 5) { + for (; offset >= firstDigit; offset--) { + if (val[offset] == '.') + continue; + digit = (int)(val[offset]) - 47; // ascii to int + 1 + if (digit != 10) break; + val.Remove(offset, 1); + } + if (digit == 10) { + // carry over, shift the result + if (val[firstDigit+1] == '.') { + val[firstDigit+1] = '0'; + val[firstDigit] = '.'; + } + val.Insert('1', 1, firstDigit); + + //remove the exponent value and the last digit + offset = val.FindFirst('E'); + if (offset == B_ERROR) + offset = val.CountChars(); + val.Truncate(--offset); + offset--; //offset now points to the last digit + + // increase the exponent and add it back to the string + exponent++; + val << 'E' << exponent; + } else { + // increase the current digit value with one + val[offset] = char(digit + 48); + } + } + + // remove trailing zeros + while (val[offset] == '0') + val.Remove(offset--, 1); + + // there is no need to keep the period if no digits follow + if (val[offset] == '.') + val.Remove(offset, 1); + } + + // set the new value + SetExpression(val); +} + + void ExpressionTextView::BackSpace() { diff --git a/src/apps/deskcalc/ExpressionTextView.h b/src/apps/deskcalc/ExpressionTextView.h index ad3ae1a281..77b49a494d 100644 --- a/src/apps/deskcalc/ExpressionTextView.h +++ b/src/apps/deskcalc/ExpressionTextView.h @@ -32,6 +32,7 @@ class ExpressionTextView : public InputTextView { virtual void GetDragParameters(BMessage* dragMessage, BBitmap** bitmap, BPoint* point, BHandler** handler); + void SetTextRect(BRect rect); // InputTextView virtual void RevertChanges(); @@ -41,6 +42,7 @@ class ExpressionTextView : public InputTextView { void AddKeypadLabel(const char* label); void SetExpression(const char* expression); + void SetValue(const char* value); void BackSpace(); void Clear(); @@ -59,6 +61,9 @@ class ExpressionTextView : public InputTextView { BList fPreviousExpressions; int32 fHistoryPos; BString fCurrentExpression; + BString fCurrentValue; + + bool fChangesApplied; }; #endif // EXPRESSION_TEXT_VIEW_H