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
This commit is contained in:
Stephan Aßmus 2010-04-21 17:20:29 +00:00
parent d7fcb36f2b
commit 665c794f1d
3 changed files with 173 additions and 7 deletions

View File

@ -917,7 +917,7 @@ CalcView::Evaluate()
}
// render new result to display
fExpressionTextView->SetExpression(value.String());
fExpressionTextView->SetValue(value.String());
}

View File

@ -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()
{

View File

@ -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