Ticket #5203: deskcalc-wim.diff

File deskcalc-wim.diff, 6.2 KB (added by Wim, 14 years ago)

Fit calculations results to the window, switching to scientific notation if necessary, rounding the value

  • deskcalc/ExpressionTextView.cpp

     
    3030    fKeypadLabels(""),
    3131    fPreviousExpressions(20),
    3232    fHistoryPos(0),
    33     fCurrentExpression("")
     33    fCurrentExpression(""),
     34    fCurrentValue(""),
     35    fChangesApplied(false)
    3436{
    3537    SetStylable(false);
    3638    SetDoesUndo(true);
     
    9193    // end of the expression history
    9294    if (current != Text())
    9395        fHistoryPos = fPreviousExpressions.CountItems();
     96       
     97    // if changes where not applied the value has become a new expression
     98    // note that even if only the left or right arrow keys are pressed the
     99    // fCurrentValue string will be cleared
     100    if (!fChangesApplied)
     101        fCurrentValue.SetTo("");
     102    else
     103        fChangesApplied = false;
    94104}
    95105
    96106
     
    117127}
    118128
    119129
     130void
     131ExpressionTextView::SetTextRect(BRect rect)
     132{
     133    InputTextView::SetTextRect(rect);
     134   
     135    int32 count = fPreviousExpressions.CountItems();
     136    if (fHistoryPos == count && fCurrentValue.CountChars() > 0) {
     137        SetValue(fCurrentValue.String());
     138    }
     139}
     140
     141
    120142// #pragma mark -
    121143
    122144
     
    133155    AddExpressionToHistory(Text());
    134156    fCalcView->FlashKey("=", 1);
    135157    fCalcView->Evaluate();
     158    fChangesApplied = true;
    136159}
    137160
    138161
     
    156179
    157180
    158181void
     182ExpressionTextView::SetValue(const char* value)
     183{
     184    // copy the value string so we can modify it
     185    BString val(value);
     186   
     187    // save the value
     188    fCurrentValue = val;
     189
     190    // calculate the width of the string
     191    BFont font;
     192    uint32 mode = B_FONT_ALL;
     193    GetFontAndColor(&font, &mode);
     194    float stringWidth = font.StringWidth(val);
     195   
     196    // make the string shorter if it does not fit in the view
     197    float viewWidth = Frame().Width();
     198    if (val.CountChars() > 3 && stringWidth > viewWidth) {
     199       
     200        // get the position of the first digit
     201        int32 firstDigit = 0;
     202        if (val[0] == '-')
     203            firstDigit++;
     204
     205        // calculate the value of the exponent
     206        int32 exponent = 0;
     207        int32 offset = val.FindFirst('.');
     208        if (offset == B_ERROR) {
     209            exponent = val.CountChars() - 1 - firstDigit;
     210            val.Insert('.', 1, firstDigit + 1);
     211        } else {
     212            if (offset == firstDigit + 1) {
     213                // if the value is 0.01 or larger then scientific notation
     214                // won't shorten the string
     215                if (val[firstDigit] != '0' || val[firstDigit+2] != '0'
     216                    || val[firstDigit+3] != '0') {
     217                        exponent = 0;
     218                } else {
     219                    // remove the period
     220                    val.Remove(offset, 1);
     221                   
     222                    // check for negative exponent value
     223                    exponent = 0;
     224                    while (val[firstDigit] == '0') {
     225                        val.Remove(firstDigit, 1);
     226                        exponent--;
     227                    }
     228                   
     229                    //add the period
     230                    val.Insert('.', 1, firstDigit + 1);
     231                }
     232            } else {
     233                // if the period + 1 digit fits in the view scientific notation
     234                // won't shorten the string
     235                BString temp = val;
     236                temp.Truncate(offset + 2);
     237                stringWidth = font.StringWidth(temp);
     238                if (stringWidth < viewWidth) {
     239                    exponent = 0;
     240                } else {
     241                    // move the period
     242                    val.Remove(offset, 1);
     243                    val.Insert('.', 1, firstDigit + 1);
     244                   
     245                    exponent = offset - (firstDigit + 1);
     246                }
     247            }
     248        }
     249       
     250        // add the exponent
     251        offset = val.CountChars() - 1;
     252        if (exponent != 0)
     253            val << "E" << exponent;
     254       
     255        // reduce the number of digits until the string fits or can not be
     256        // made any shorter
     257        stringWidth = font.StringWidth(val);
     258        char lastRemovedDigit = '0';
     259        while (offset > firstDigit && stringWidth > viewWidth) {
     260            if (val[offset] != '.')
     261                lastRemovedDigit = val[offset];
     262            val.Remove(offset--, 1);
     263            stringWidth = font.StringWidth(val);
     264        }
     265       
     266        // there is no need to keep the period if no digits follow
     267        if (val[offset] == '.') {
     268            val.Remove(offset, 1);
     269            offset--;
     270        }
     271       
     272        // take care of proper rounding of the result
     273        int digit = (int)lastRemovedDigit - 48; // ascii to int
     274        if (digit >= 5) {
     275            for (; offset >= firstDigit; offset--) {
     276                if (val[offset] == '.')
     277                    continue;
     278                digit = (int)(val[offset]) - 47; // ascii to int + 1
     279                if (digit != 10) break;
     280                val.Remove(offset, 1);
     281            }
     282            if (digit == 10) {
     283                // carry over, shift the result
     284                if (val[firstDigit+1] == '.') {
     285                    val[firstDigit+1] = '0';
     286                    val[firstDigit] = '.';
     287                }
     288                val.Insert('1', 1, firstDigit);
     289               
     290                //remove the exponent value and the last digit
     291                offset = val.FindFirst('E');
     292                if (offset == B_ERROR)
     293                    offset = val.CountChars();
     294                val.Truncate(--offset);
     295                offset--; //offset now points to the last digit
     296               
     297                // increase the exponent and add it back to the string
     298                exponent++;
     299                val << 'E' << exponent;
     300            } else {
     301                // increase the current digit value with one
     302                val[offset] = char(digit + 48);
     303            }
     304        }
     305       
     306        // remove trailing zeros
     307        while (val[offset] == '0')
     308            val.Remove(offset--, 1);
     309       
     310        // there is no need to keep the period if no digits follow
     311        if (val[offset] == '.')
     312            val.Remove(offset, 1);
     313    }
     314
     315    // set the new value   
     316    SetExpression(val);
     317}
     318
     319
     320void
    159321ExpressionTextView::BackSpace()
    160322{
    161323    const char bytes[1] = { B_BACKSPACE };
  • deskcalc/ExpressionTextView.h

     
    3232    virtual void                GetDragParameters(BMessage* dragMessage,
    3333                                    BBitmap** bitmap, BPoint* point,
    3434                                    BHandler** handler);
     35            void                SetTextRect(BRect rect);
    3536
    3637    // InputTextView
    3738    virtual void                RevertChanges();
     
    4142            void                AddKeypadLabel(const char* label);
    4243
    4344            void                SetExpression(const char* expression);
     45            void                SetValue(const char* value);
    4446
    4547            void                BackSpace();
    4648            void                Clear();
     
    5961            BList               fPreviousExpressions;
    6062            int32               fHistoryPos;
    6163            BString             fCurrentExpression;
     64            BString             fCurrentValue;
     65           
     66            bool                fChangesApplied;
    6267};
    6368
    6469#endif // EXPRESSION_TEXT_VIEW_H
  • deskcalc/CalcView.cpp

     
    917917    }
    918918
    919919    // render new result to display
    920     fExpressionTextView->SetExpression(value.String());
     920    fExpressionTextView->SetValue(value.String());
    921921}
    922922
    923923