| 182 | ExpressionTextView::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 | |
| 320 | void |