Author: stippi Date: 2010-04-21 19:20:29 +0200 (Wed, 21 Apr 2010) New Revision: 36402 Changeset: http://dev.haiku-os.org/changeset/36402/haiku Ticket: http://dev.haiku-os.org/ticket/5203 Modified: haiku/trunk/src/apps/deskcalc/CalcView.cpp haiku/trunk/src/apps/deskcalc/ExpressionTextView.cpp haiku/trunk/src/apps/deskcalc/ExpressionTextView.h Log: 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. Modified: haiku/trunk/src/apps/deskcalc/CalcView.cpp =================================================================== --- haiku/trunk/src/apps/deskcalc/CalcView.cpp 2010-04-21 16:46:32 UTC (rev 36401) +++ haiku/trunk/src/apps/deskcalc/CalcView.cpp 2010-04-21 17:20:29 UTC (rev 36402) @@ -917,7 +917,7 @@ } // render new result to display - fExpressionTextView->SetExpression(value.String()); + fExpressionTextView->SetValue(value.String()); } Modified: haiku/trunk/src/apps/deskcalc/ExpressionTextView.cpp =================================================================== --- haiku/trunk/src/apps/deskcalc/ExpressionTextView.cpp 2010-04-21 16:46:32 UTC (rev 36401) +++ haiku/trunk/src/apps/deskcalc/ExpressionTextView.cpp 2010-04-21 17:20:29 UTC (rev 36402) @@ -30,7 +30,9 @@ fKeypadLabels(""), fPreviousExpressions(20), fHistoryPos(0), - fCurrentExpression("") + fCurrentExpression(""), + fCurrentValue(""), + fChangesApplied(false) { SetStylable(false); SetDoesUndo(true); @@ -64,7 +66,7 @@ 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 @@ } 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 @@ } +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 @@ AddExpressionToHistory(Text()); fCalcView->FlashKey("=", 1); fCalcView->Evaluate(); + fChangesApplied = true; } @@ -156,6 +178,145 @@ 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() { const char bytes[1] = { B_BACKSPACE }; Modified: haiku/trunk/src/apps/deskcalc/ExpressionTextView.h =================================================================== --- haiku/trunk/src/apps/deskcalc/ExpressionTextView.h 2010-04-21 16:46:32 UTC (rev 36401) +++ haiku/trunk/src/apps/deskcalc/ExpressionTextView.h 2010-04-21 17:20:29 UTC (rev 36402) @@ -32,6 +32,7 @@ virtual void GetDragParameters(BMessage* dragMessage, BBitmap** bitmap, BPoint* point, BHandler** handler); + void SetTextRect(BRect rect); // InputTextView virtual void RevertChanges(); @@ -41,6 +42,7 @@ void AddKeypadLabel(const char* label); void SetExpression(const char* expression); + void SetValue(const char* value); void BackSpace(); void Clear(); @@ -59,6 +61,9 @@ BList fPreviousExpressions; int32 fHistoryPos; BString fCurrentExpression; + BString fCurrentValue; + + bool fChangesApplied; }; #endif // EXPRESSION_TEXT_VIEW_H