1 /* 2 * Copyright 2006-2013, Haiku, Inc. All rights reserved. 3 * Copyright 1997, 1998 R3 Software Ltd. All Rights Reserved. 4 * Distributed under the terms of the MIT License. 5 * 6 * Authors: 7 * Stephan Aßmus, superstippi@gmx.de 8 * Philippe Saint-Pierre, stpere@gmail.com 9 * John Scipione, jscipione@gmail.com 10 * Timothy Wayper, timmy@wunderbear.com 11 */ 12 13 14 #include "CalcView.h" 15 16 #include <stdlib.h> 17 #include <stdio.h> 18 #include <string.h> 19 #include <ctype.h> 20 #include <assert.h> 21 22 #include <AboutWindow.h> 23 #include <Alert.h> 24 #include <Application.h> 25 #include <AppFileInfo.h> 26 #include <AutoLocker.h> 27 #include <Beep.h> 28 #include <Bitmap.h> 29 #include <Catalog.h> 30 #include <ControlLook.h> 31 #include <Clipboard.h> 32 #include <File.h> 33 #include <Font.h> 34 #include <Locale.h> 35 #include <MenuItem.h> 36 #include <Message.h> 37 #include <MessageRunner.h> 38 #include <NumberFormat.h> 39 #include <Point.h> 40 #include <PopUpMenu.h> 41 #include <Region.h> 42 #include <Roster.h> 43 44 #include <ExpressionParser.h> 45 46 #include "CalcApplication.h" 47 #include "CalcOptions.h" 48 #include "ExpressionTextView.h" 49 50 51 #undef B_TRANSLATION_CONTEXT 52 #define B_TRANSLATION_CONTEXT "CalcView" 53 54 55 static const int32 kMsgCalculating = 'calc'; 56 static const int32 kMsgAnimateDots = 'dots'; 57 static const int32 kMsgDoneEvaluating = 'done'; 58 59 //const uint8 K_COLOR_OFFSET = 32; 60 const float kFontScaleY = 0.4f; 61 const float kFontScaleX = 0.4f; 62 const float kExpressionFontScaleY = 0.6f; 63 const float kDisplayScaleY = 0.2f; 64 65 static const bigtime_t kFlashOnOffInterval = 100000; 66 static const bigtime_t kCalculatingInterval = 1000000; 67 static const bigtime_t kAnimationInterval = 333333; 68 69 static const float kMinimumWidthCompact = 130.0f; 70 static const float kMaximumWidthCompact = 400.0f; 71 static const float kMinimumHeightCompact = 20.0f; 72 static const float kMaximumHeightCompact = 60.0f; 73 74 // Basic mode size limits are defined in CalcView.h so 75 // that they can be used by the CalcWindow constructor. 76 77 static const float kMinimumWidthScientific = 240.0f; 78 static const float kMaximumWidthScientific = 400.0f; 79 static const float kMinimumHeightScientific = 200.0f; 80 static const float kMaximumHeightScientific = 400.0f; 81 82 // basic mode keypad layout (default) 83 const char *kKeypadDescriptionBasic[] = { 84 B_TRANSLATE_MARK("7"), 85 B_TRANSLATE_MARK("8"), 86 B_TRANSLATE_MARK("9"), 87 B_TRANSLATE_MARK("("), 88 B_TRANSLATE_MARK(")"), 89 "\n", 90 B_TRANSLATE_MARK("4"), 91 B_TRANSLATE_MARK("5"), 92 B_TRANSLATE_MARK("6"), 93 B_TRANSLATE_MARK("*"), 94 B_TRANSLATE_MARK("/"), 95 "\n", 96 B_TRANSLATE_MARK("1"), 97 B_TRANSLATE_MARK("2"), 98 B_TRANSLATE_MARK("3"), 99 B_TRANSLATE_MARK("+"), 100 B_TRANSLATE_MARK("-"), 101 "\n", 102 B_TRANSLATE_MARK("0"), 103 B_TRANSLATE_MARK("."), 104 B_TRANSLATE_MARK("BS"), 105 B_TRANSLATE_MARK("="), 106 B_TRANSLATE_MARK("C"), 107 "\n", 108 NULL 109 }; 110 111 // scientific mode keypad layout 112 const char *kKeypadDescriptionScientific[] = { 113 B_TRANSLATE_MARK("ln"), 114 B_TRANSLATE_MARK("sin"), 115 B_TRANSLATE_MARK("cos"), 116 B_TRANSLATE_MARK("tan"), 117 B_TRANSLATE_MARK("π"), 118 "\n", 119 B_TRANSLATE_MARK("log"), 120 B_TRANSLATE_MARK("asin"), 121 B_TRANSLATE_MARK("acos"), 122 B_TRANSLATE_MARK("atan"), 123 B_TRANSLATE_MARK("sqrt"), 124 "\n", 125 B_TRANSLATE_MARK("exp"), 126 B_TRANSLATE_MARK("sinh"), 127 B_TRANSLATE_MARK("cosh"), 128 B_TRANSLATE_MARK("tanh"), 129 B_TRANSLATE_MARK("cbrt"), 130 "\n", 131 B_TRANSLATE_MARK("!"), 132 B_TRANSLATE_MARK("ceil"), 133 B_TRANSLATE_MARK("floor"), 134 B_TRANSLATE_MARK("E"), 135 B_TRANSLATE_MARK("^"), 136 "\n", 137 B_TRANSLATE_MARK("7"), 138 B_TRANSLATE_MARK("8"), 139 B_TRANSLATE_MARK("9"), 140 B_TRANSLATE_MARK("("), 141 B_TRANSLATE_MARK(")"), 142 "\n", 143 B_TRANSLATE_MARK("4"), 144 B_TRANSLATE_MARK("5"), 145 B_TRANSLATE_MARK("6"), 146 B_TRANSLATE_MARK("*"), 147 B_TRANSLATE_MARK("/"), 148 "\n", 149 B_TRANSLATE_MARK("1"), 150 B_TRANSLATE_MARK("2"), 151 B_TRANSLATE_MARK("3"), 152 B_TRANSLATE_MARK("+"), 153 B_TRANSLATE_MARK("-"), 154 "\n", 155 B_TRANSLATE_MARK("0"), 156 B_TRANSLATE_MARK("."), 157 B_TRANSLATE_MARK("BS"), 158 B_TRANSLATE_MARK("="), 159 B_TRANSLATE_MARK("C"), 160 "\n", 161 NULL 162 }; 163 164 165 enum { 166 FLAGS_FLASH_KEY = 1 << 0, 167 FLAGS_MOUSE_DOWN = 1 << 1 168 }; 169 170 171 struct CalcView::CalcKey { 172 char label[8]; 173 char code[8]; 174 char keymap[4]; 175 uint32 flags; 176 // float width; 177 }; 178 179 180 typedef AutoLocker<BClipboard> ClipboardLocker; 181 182 183 CalcView* 184 CalcView::Instantiate(BMessage* archive) 185 { 186 if (!validate_instantiation(archive, "CalcView")) 187 return NULL; 188 189 return new CalcView(archive); 190 } 191 192 193 CalcView::CalcView(BRect frame, rgb_color rgbBaseColor, BMessage* settings) 194 : 195 BView(frame, "DeskCalc", B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_FRAME_EVENTS), 196 197 fColumns(5), 198 fRows(4), 199 200 fBaseColor(rgbBaseColor), 201 fHasCustomBaseColor(rgbBaseColor != ui_color(B_PANEL_BACKGROUND_COLOR)), 202 203 fWidth(1), 204 fHeight(1), 205 206 fKeypadDescription(kKeypadDescriptionBasic), 207 fKeypad(NULL), 208 209 fCalcIcon(new BBitmap(BRect(0, 0, 15, 15), 0, B_RGBA32)), 210 211 fPopUpMenu(NULL), 212 fAutoNumlockItem(NULL), 213 fOptions(new CalcOptions()), 214 fEvaluateThread(-1), 215 fEvaluateMessageRunner(NULL), 216 fEvaluateSemaphore(B_BAD_SEM_ID), 217 fEnabled(true) 218 { 219 // tell the app server not to erase our b/g 220 SetViewColor(B_TRANSPARENT_32_BIT); 221 222 _Init(settings); 223 } 224 225 226 CalcView::CalcView(BMessage* archive) 227 : 228 BView(archive), 229 230 fColumns(5), 231 fRows(4), 232 233 fBaseColor(ui_color(B_PANEL_BACKGROUND_COLOR)), 234 235 fHasCustomBaseColor(false), 236 237 fWidth(1), 238 fHeight(1), 239 240 fKeypadDescription(kKeypadDescriptionBasic), 241 fKeypad(NULL), 242 243 fCalcIcon(new BBitmap(BRect(0, 0, 15, 15), 0, B_RGBA32)), 244 245 fPopUpMenu(NULL), 246 fAutoNumlockItem(NULL), 247 fOptions(new CalcOptions()), 248 fEvaluateThread(-1), 249 fEvaluateMessageRunner(NULL), 250 fEvaluateSemaphore(B_BAD_SEM_ID), 251 fEnabled(true) 252 { 253 // Do not restore the follow mode, in shelfs, we never follow. 254 SetResizingMode(B_FOLLOW_NONE); 255 256 _Init(archive); 257 } 258 259 260 CalcView::~CalcView() 261 { 262 delete[] fKeypad; 263 delete fOptions; 264 delete fEvaluateMessageRunner; 265 delete_sem(fEvaluateSemaphore); 266 } 267 268 269 void 270 CalcView::AttachedToWindow() 271 { 272 if (be_control_look == NULL) 273 SetFont(be_bold_font); 274 275 BRect frame(Frame()); 276 FrameResized(frame.Width(), frame.Height()); 277 278 bool addKeypadModeMenuItems = true; 279 if (Parent() && (Parent()->Flags() & B_DRAW_ON_CHILDREN) != 0) { 280 // don't add these items if we are a replicant on the desktop 281 addKeypadModeMenuItems = false; 282 } 283 284 // create and attach the pop-up menu 285 _CreatePopUpMenu(addKeypadModeMenuItems); 286 287 if (addKeypadModeMenuItems) 288 SetKeypadMode(fOptions->keypad_mode); 289 } 290 291 292 void 293 CalcView::MessageReceived(BMessage* message) 294 { 295 if (message->what == B_COLORS_UPDATED) { 296 const char* panelBgColorName = ui_color_name(B_PANEL_BACKGROUND_COLOR); 297 if (message->HasColor(panelBgColorName) && !fHasCustomBaseColor) { 298 fBaseColor = message->GetColor(panelBgColorName, fBaseColor); 299 _Colorize(); 300 } 301 if (message->HasColor(ui_color_name(B_PANEL_TEXT_COLOR))) 302 _Colorize(); 303 304 return; 305 } 306 307 if (Parent() && (Parent()->Flags() & B_DRAW_ON_CHILDREN) != 0) { 308 // if we are embedded in desktop we need to receive these 309 // message here since we don't have a parent BWindow 310 switch (message->what) { 311 case MSG_OPTIONS_AUTO_NUM_LOCK: 312 ToggleAutoNumlock(); 313 return; 314 315 case MSG_OPTIONS_ANGLE_MODE_RADIAN: 316 SetDegreeMode(false); 317 return; 318 319 case MSG_OPTIONS_ANGLE_MODE_DEGREE: 320 SetDegreeMode(true); 321 return; 322 } 323 } 324 325 // check if message was dropped 326 if (message->WasDropped()) { 327 // pass message on to paste 328 if (message->IsSourceRemote()) 329 Paste(message); 330 } else { 331 // act on posted message type 332 switch (message->what) { 333 334 // handle "cut" 335 case B_CUT: 336 Cut(); 337 break; 338 339 // handle copy 340 case B_COPY: 341 Copy(); 342 break; 343 344 // handle paste 345 case B_PASTE: 346 { 347 // access system clipboard 348 ClipboardLocker locker(be_clipboard); 349 if (locker.IsLocked()) { 350 BMessage* clipper = be_clipboard->Data(); 351 if (clipper) 352 Paste(clipper); 353 } 354 break; 355 } 356 357 // (replicant) about box requested 358 case B_ABOUT_REQUESTED: 359 { 360 BAboutWindow* window = new BAboutWindow(kAppName, kSignature); 361 362 // create the about window 363 const char* extraCopyrights[] = { 364 "1997, 1998 R3 Software Ltd.", 365 NULL 366 }; 367 368 const char* authors[] = { 369 "Stephan Aßmus", 370 "John Scipione", 371 "Timothy Wayper", 372 "Ingo Weinhold", 373 NULL 374 }; 375 376 window->AddCopyright(2006, "Haiku, Inc.", extraCopyrights); 377 window->AddAuthors(authors); 378 379 window->Show(); 380 381 break; 382 } 383 384 case MSG_UNFLASH_KEY: 385 { 386 int32 key; 387 if (message->FindInt32("key", &key) == B_OK) 388 _FlashKey(key, 0); 389 390 break; 391 } 392 393 case kMsgAnimateDots: 394 { 395 int32 end = fExpressionTextView->TextLength(); 396 int32 start = end - 3; 397 if (fEnabled || strcmp(fExpressionTextView->Text() + start, 398 "...") != 0) { 399 // stop the message runner 400 delete fEvaluateMessageRunner; 401 fEvaluateMessageRunner = NULL; 402 break; 403 } 404 405 uint8 dot = 0; 406 if (message->FindUInt8("dot", &dot) == B_OK) { 407 rgb_color fontColor = fExpressionTextView->HighColor(); 408 rgb_color backColor = fExpressionTextView->LowColor(); 409 fExpressionTextView->SetStylable(true); 410 fExpressionTextView->SetFontAndColor(start, end, NULL, 0, 411 &backColor); 412 fExpressionTextView->SetFontAndColor(start + dot - 1, 413 start + dot, NULL, 0, &fontColor); 414 fExpressionTextView->SetStylable(false); 415 } 416 417 dot++; 418 if (dot == 4) 419 dot = 1; 420 421 delete fEvaluateMessageRunner; 422 BMessage animate(kMsgAnimateDots); 423 animate.AddUInt8("dot", dot); 424 fEvaluateMessageRunner = new (std::nothrow) BMessageRunner( 425 BMessenger(this), &animate, kAnimationInterval, 1); 426 break; 427 } 428 429 case kMsgCalculating: 430 { 431 // calculation has taken more than 3 seconds 432 if (fEnabled) { 433 // stop the message runner 434 delete fEvaluateMessageRunner; 435 fEvaluateMessageRunner = NULL; 436 break; 437 } 438 439 BString calculating; 440 calculating << B_TRANSLATE("Calculating") << "..."; 441 fExpressionTextView->SetText(calculating.String()); 442 443 delete fEvaluateMessageRunner; 444 BMessage animate(kMsgAnimateDots); 445 animate.AddUInt8("dot", 1U); 446 fEvaluateMessageRunner = new (std::nothrow) BMessageRunner( 447 BMessenger(this), &animate, kAnimationInterval, 1); 448 break; 449 } 450 451 case kMsgDoneEvaluating: 452 { 453 _SetEnabled(true); 454 rgb_color fontColor = fExpressionTextView->HighColor(); 455 fExpressionTextView->SetFontAndColor(NULL, 0, &fontColor); 456 457 const char* result; 458 if (message->FindString("error", &result) == B_OK) 459 fExpressionTextView->SetText(result); 460 else if (message->FindString("value", &result) == B_OK) { 461 BLocale locale; 462 BNumberFormat format(&locale); 463 464 fExpressionTextView->SetValue(result, format.GetSeparator(B_DECIMAL_SEPARATOR)); 465 } 466 467 // stop the message runner 468 delete fEvaluateMessageRunner; 469 fEvaluateMessageRunner = NULL; 470 break; 471 } 472 473 default: 474 BView::MessageReceived(message); 475 break; 476 } 477 } 478 } 479 480 481 void 482 CalcView::Draw(BRect updateRect) 483 { 484 bool drawBackground = !_IsEmbedded(); 485 486 SetHighColor(fBaseColor); 487 BRect expressionRect(_ExpressionRect()); 488 if (updateRect.Intersects(expressionRect)) { 489 if (fOptions->keypad_mode == KEYPAD_MODE_COMPACT 490 && expressionRect.Height() >= fCalcIcon->Bounds().Height()) { 491 // render calc icon 492 expressionRect.left = fExpressionTextView->Frame().right + 2; 493 if (drawBackground) { 494 SetHighColor(fBaseColor); 495 FillRect(updateRect & expressionRect); 496 } 497 498 SetDrawingMode(B_OP_ALPHA); 499 SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 500 501 BPoint iconPos; 502 iconPos.x = expressionRect.right - (expressionRect.Width() 503 + fCalcIcon->Bounds().Width()) / 2.0; 504 iconPos.y = expressionRect.top + (expressionRect.Height() 505 - fCalcIcon->Bounds().Height()) / 2.0; 506 DrawBitmap(fCalcIcon, iconPos); 507 508 SetDrawingMode(B_OP_COPY); 509 } 510 511 // render border around expression text view 512 expressionRect = fExpressionTextView->Frame(); 513 expressionRect.InsetBy(-2, -2); 514 if (fOptions->keypad_mode != KEYPAD_MODE_COMPACT && drawBackground) { 515 expressionRect.InsetBy(-2, -2); 516 StrokeRect(expressionRect); 517 expressionRect.InsetBy(1, 1); 518 StrokeRect(expressionRect); 519 expressionRect.InsetBy(1, 1); 520 } 521 522 uint32 flags = 0; 523 if (!drawBackground) 524 flags |= BControlLook::B_BLEND_FRAME; 525 be_control_look->DrawTextControlBorder(this, expressionRect, 526 updateRect, fBaseColor, flags); 527 } 528 529 if (fOptions->keypad_mode == KEYPAD_MODE_COMPACT) 530 return; 531 532 // calculate grid sizes 533 BRect keypadRect(_KeypadRect()); 534 535 if (be_control_look != NULL) { 536 if (drawBackground) 537 StrokeRect(keypadRect); 538 keypadRect.InsetBy(1, 1); 539 } 540 541 float sizeDisp = keypadRect.top; 542 float sizeCol = (keypadRect.Width() + 1) / (float)fColumns; 543 float sizeRow = (keypadRect.Height() + 1) / (float)fRows; 544 545 if (!updateRect.Intersects(keypadRect)) 546 return; 547 548 SetFontSize(min_c(sizeRow * kFontScaleY, sizeCol * kFontScaleX)); 549 550 CalcKey* key = fKeypad; 551 for (int row = 0; row < fRows; row++) { 552 for (int col = 0; col < fColumns; col++) { 553 BRect frame; 554 frame.left = keypadRect.left + col * sizeCol; 555 frame.right = keypadRect.left + (col + 1) * sizeCol - 1; 556 frame.top = sizeDisp + row * sizeRow; 557 frame.bottom = sizeDisp + (row + 1) * sizeRow - 1; 558 559 if (drawBackground) { 560 SetHighColor(fBaseColor); 561 StrokeRect(frame); 562 } 563 frame.InsetBy(1, 1); 564 565 uint32 flags = 0; 566 if (!drawBackground) 567 flags |= BControlLook::B_BLEND_FRAME; 568 if (key->flags != 0) 569 flags |= BControlLook::B_ACTIVATED; 570 flags |= BControlLook::B_IGNORE_OUTLINE; 571 572 be_control_look->DrawButtonFrame(this, frame, updateRect, 573 fBaseColor, fBaseColor, flags); 574 575 be_control_look->DrawButtonBackground(this, frame, updateRect, 576 fBaseColor, flags); 577 578 be_control_look->DrawLabel(this, key->label, frame, updateRect, 579 fBaseColor, flags, BAlignment(B_ALIGN_HORIZONTAL_CENTER, 580 B_ALIGN_VERTICAL_CENTER), &fButtonTextColor); 581 582 key++; 583 } 584 } 585 } 586 587 588 void 589 CalcView::MouseDown(BPoint point) 590 { 591 // ensure this view is the current focus 592 if (!fExpressionTextView->IsFocus()) { 593 // Call our version of MakeFocus(), since that will also apply the 594 // num_lock setting. 595 MakeFocus(); 596 } 597 598 // read mouse buttons state 599 int32 buttons = 0; 600 Window()->CurrentMessage()->FindInt32("buttons", &buttons); 601 602 if ((B_PRIMARY_MOUSE_BUTTON & buttons) == 0) { 603 // display popup menu if not primary mouse button 604 BMenuItem* selected; 605 if ((selected = fPopUpMenu->Go(ConvertToScreen(point))) != NULL 606 && selected->Message() != NULL) { 607 Window()->PostMessage(selected->Message(), this); 608 } 609 return; 610 } 611 612 if (fOptions->keypad_mode == KEYPAD_MODE_COMPACT) { 613 if (fCalcIcon != NULL) { 614 BRect bounds(Bounds()); 615 bounds.left = bounds.right - fCalcIcon->Bounds().Width(); 616 if (bounds.Contains(point)) { 617 // user clicked on calculator icon 618 fExpressionTextView->Clear(); 619 } 620 } 621 return; 622 } 623 624 // calculate grid sizes 625 float sizeDisp = fHeight * kDisplayScaleY; 626 float sizeCol = fWidth / (float)fColumns; 627 float sizeRow = (fHeight - sizeDisp) / (float)fRows; 628 629 // calculate location within grid 630 int gridCol = (int)floorf(point.x / sizeCol); 631 int gridRow = (int)floorf((point.y - sizeDisp) / sizeRow); 632 633 // check limits 634 if ((gridCol >= 0) && (gridCol < fColumns) 635 && (gridRow >= 0) && (gridRow < fRows)) { 636 637 // process key press 638 int key = gridRow * fColumns + gridCol; 639 _FlashKey(key, FLAGS_MOUSE_DOWN); 640 _PressKey(key); 641 642 // make sure we receive the mouse up! 643 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); 644 } 645 } 646 647 648 void 649 CalcView::MouseUp(BPoint point) 650 { 651 if (fOptions->keypad_mode == KEYPAD_MODE_COMPACT) 652 return; 653 654 int keys = fRows * fColumns; 655 for (int i = 0; i < keys; i++) { 656 if (fKeypad[i].flags & FLAGS_MOUSE_DOWN) { 657 _FlashKey(i, 0); 658 break; 659 } 660 } 661 } 662 663 664 void 665 CalcView::KeyDown(const char* bytes, int32 numBytes) 666 { 667 // if single byte character... 668 if (numBytes == 1) { 669 670 //printf("Key pressed: %c\n", bytes[0]); 671 672 switch (bytes[0]) { 673 674 case B_ENTER: 675 // translate to evaluate key 676 _PressKey("="); 677 break; 678 679 case B_LEFT_ARROW: 680 case B_BACKSPACE: 681 // translate to backspace key 682 _PressKey("BS"); 683 break; 684 685 case B_SPACE: 686 case B_ESCAPE: 687 case 'c': 688 // translate to clear key 689 _PressKey("C"); 690 break; 691 692 // bracket translation 693 case '[': 694 case '{': 695 _PressKey("("); 696 break; 697 698 case ']': 699 case '}': 700 _PressKey(")"); 701 break; 702 703 default: { 704 // scan the keymap array for match 705 int keys = fRows * fColumns; 706 for (int i = 0; i < keys; i++) { 707 if (fKeypad[i].keymap[0] == bytes[0]) { 708 _PressKey(i); 709 return; 710 } 711 } 712 break; 713 } 714 } 715 } 716 } 717 718 719 void 720 CalcView::MakeFocus(bool focused) 721 { 722 if (focused) { 723 // set num lock 724 if (fOptions->auto_num_lock) { 725 set_keyboard_locks(B_NUM_LOCK 726 | (modifiers() & (B_CAPS_LOCK | B_SCROLL_LOCK))); 727 } 728 } 729 730 // pass on request to text view 731 fExpressionTextView->MakeFocus(focused); 732 } 733 734 735 void 736 CalcView::FrameResized(float width, float height) 737 { 738 fWidth = width; 739 fHeight = height; 740 741 // layout expression text view 742 BRect expressionRect = _ExpressionRect(); 743 if (fOptions->keypad_mode == KEYPAD_MODE_COMPACT) { 744 expressionRect.InsetBy(2, 2); 745 expressionRect.right -= ceilf(fCalcIcon->Bounds().Width() * 1.5); 746 } else 747 expressionRect.InsetBy(4, 4); 748 749 fExpressionTextView->MoveTo(expressionRect.LeftTop()); 750 fExpressionTextView->ResizeTo(expressionRect.Width(), expressionRect.Height()); 751 752 // configure expression text view font size and color 753 float sizeDisp = fOptions->keypad_mode == KEYPAD_MODE_COMPACT 754 ? fHeight : fHeight * kDisplayScaleY; 755 BFont font(be_bold_font); 756 font.SetSize(sizeDisp * kExpressionFontScaleY); 757 rgb_color fontColor = fExpressionTextView->HighColor(); 758 fExpressionTextView->SetFontAndColor(&font, B_FONT_ALL, &fontColor); 759 760 expressionRect.OffsetTo(B_ORIGIN); 761 fExpressionTextView->SetTextRect(expressionRect); 762 Invalidate(); 763 } 764 765 766 status_t 767 CalcView::Archive(BMessage* archive, bool deep) const 768 { 769 fExpressionTextView->RemoveSelf(); 770 771 // passed on request to parent 772 status_t ret = BView::Archive(archive, deep); 773 774 const_cast<CalcView*>(this)->AddChild(fExpressionTextView); 775 776 // save app signature for replicant add-on loading 777 if (ret == B_OK) 778 ret = archive->AddString("add_on", kSignature); 779 780 // save all the options 781 if (ret == B_OK) 782 ret = SaveSettings(archive); 783 784 // add class info last 785 if (ret == B_OK) 786 ret = archive->AddString("class", "CalcView"); 787 788 return ret; 789 } 790 791 792 void 793 CalcView::Cut() 794 { 795 Copy(); // copy data to clipboard 796 fExpressionTextView->Clear(); // remove data 797 } 798 799 800 void 801 CalcView::Copy() 802 { 803 // access system clipboard 804 ClipboardLocker locker(be_clipboard); 805 if (!locker.IsLocked()) 806 return; 807 808 if (be_clipboard->Clear() != B_OK) 809 return; 810 811 BMessage* clipper = be_clipboard->Data(); 812 if (clipper == NULL) 813 return; 814 815 BString expression = fExpressionTextView->Text(); 816 if (clipper->AddData("text/plain", B_MIME_TYPE, 817 expression.String(), expression.Length()) == B_OK) { 818 clipper->what = B_MIME_DATA; 819 be_clipboard->Commit(); 820 } 821 } 822 823 824 void 825 CalcView::Paste(BMessage* message) 826 { 827 // handle files first 828 int32 count; 829 if (message->GetInfo("refs", NULL, &count) == B_OK) { 830 entry_ref ref; 831 ssize_t read; 832 BFile file; 833 char buffer[256]; 834 memset(buffer, 0, sizeof(buffer)); 835 for (int32 i = 0; i < count; i++) { 836 if (message->FindRef("refs", i, &ref) == B_OK) { 837 if (file.SetTo(&ref, B_READ_ONLY) == B_OK) { 838 read = file.Read(buffer, sizeof(buffer) - 1); 839 if (read <= 0) 840 continue; 841 BString expression(buffer); 842 int32 j = expression.Length(); 843 while (j > 0 && expression[j - 1] == '\n') 844 j--; 845 expression.Truncate(j); 846 if (expression.Length() > 0) 847 fExpressionTextView->Insert(expression.String()); 848 } 849 } 850 } 851 return; 852 } 853 // handle color drops 854 // read incoming color 855 const rgb_color* dropColor = NULL; 856 ssize_t dataSize; 857 if (message->FindData("RGBColor", B_RGB_COLOR_TYPE, 858 (const void**)&dropColor, &dataSize) == B_OK 859 && dataSize == sizeof(rgb_color)) { 860 861 // calculate view relative drop point 862 BPoint dropPoint = ConvertFromScreen(message->DropPoint()); 863 864 // calculate current keypad area 865 float sizeDisp = fHeight * kDisplayScaleY; 866 BRect keypadRect(0.0, sizeDisp, fWidth, fHeight); 867 868 // check location of color drop 869 if (keypadRect.Contains(dropPoint) && dropColor != NULL) { 870 fBaseColor = *dropColor; 871 fHasCustomBaseColor = 872 fBaseColor != ui_color(B_PANEL_BACKGROUND_COLOR); 873 _Colorize(); 874 // redraw 875 Invalidate(); 876 } 877 878 } else { 879 // look for text/plain MIME data 880 const char* text; 881 ssize_t numBytes; 882 if (message->FindData("text/plain", B_MIME_TYPE, 883 (const void**)&text, &numBytes) == B_OK) { 884 BString temp; 885 temp.Append(text, numBytes); 886 fExpressionTextView->Insert(temp.String()); 887 } 888 } 889 } 890 891 892 status_t 893 CalcView::SaveSettings(BMessage* archive) const 894 { 895 status_t ret = archive ? B_OK : B_BAD_VALUE; 896 897 // record grid dimensions 898 if (ret == B_OK) 899 ret = archive->AddInt16("cols", fColumns); 900 901 if (ret == B_OK) 902 ret = archive->AddInt16("rows", fRows); 903 904 // record color scheme 905 if (ret == B_OK) { 906 ret = archive->AddData("rgbBaseColor", B_RGB_COLOR_TYPE, 907 &fBaseColor, sizeof(rgb_color)); 908 } 909 910 // record current options 911 if (ret == B_OK) 912 ret = fOptions->SaveSettings(archive); 913 914 // record display text 915 if (ret == B_OK) 916 ret = archive->AddString("displayText", fExpressionTextView->Text()); 917 918 // record expression history 919 if (ret == B_OK) 920 ret = fExpressionTextView->SaveSettings(archive); 921 922 // record calculator description 923 if (ret == B_OK) 924 ret = archive->AddString("calcDesc", 925 fKeypadDescription == kKeypadDescriptionBasic 926 ? "basic" : "scientific"); 927 928 return ret; 929 } 930 931 932 void 933 CalcView::Evaluate() 934 { 935 if (fExpressionTextView->TextLength() == 0) { 936 beep(); 937 return; 938 } 939 940 fEvaluateThread = spawn_thread(_EvaluateThread, "Evaluate Thread", 941 B_LOW_PRIORITY, this); 942 if (fEvaluateThread < B_OK) { 943 // failed to create evaluate thread, error out 944 fExpressionTextView->SetText(strerror(fEvaluateThread)); 945 return; 946 } 947 948 _SetEnabled(false); 949 // Disable input while we evaluate 950 951 status_t threadStatus = resume_thread(fEvaluateThread); 952 if (threadStatus != B_OK) { 953 // evaluate thread failed to start, error out 954 fExpressionTextView->SetText(strerror(threadStatus)); 955 _SetEnabled(true); 956 return; 957 } 958 959 if (fEvaluateMessageRunner == NULL) { 960 BMessage message(kMsgCalculating); 961 fEvaluateMessageRunner = new (std::nothrow) BMessageRunner( 962 BMessenger(this), &message, kCalculatingInterval, 1); 963 status_t runnerStatus = fEvaluateMessageRunner->InitCheck(); 964 if (runnerStatus != B_OK) 965 printf("Evaluate Message Runner: %s\n", strerror(runnerStatus)); 966 } 967 } 968 969 970 void 971 CalcView::FlashKey(const char* bytes, int32 numBytes) 972 { 973 BString temp; 974 temp.Append(bytes, numBytes); 975 int32 key = _KeyForLabel(temp.String()); 976 if (key >= 0) 977 _FlashKey(key, FLAGS_FLASH_KEY); 978 } 979 980 981 void 982 CalcView::ToggleAutoNumlock(void) 983 { 984 fOptions->auto_num_lock = !fOptions->auto_num_lock; 985 fAutoNumlockItem->SetMarked(fOptions->auto_num_lock); 986 } 987 988 989 void 990 CalcView::SetDegreeMode(bool degrees) 991 { 992 fOptions->degree_mode = degrees; 993 fAngleModeRadianItem->SetMarked(!degrees); 994 fAngleModeDegreeItem->SetMarked(degrees); 995 } 996 997 998 void 999 CalcView::SetKeypadMode(uint8 mode) 1000 { 1001 if (_IsEmbedded()) 1002 return; 1003 1004 BWindow* window = Window(); 1005 if (window == NULL) 1006 return; 1007 1008 if (fOptions->keypad_mode == mode) 1009 return; 1010 1011 fOptions->keypad_mode = mode; 1012 _MarkKeypadItems(fOptions->keypad_mode); 1013 1014 float width = fWidth; 1015 float height = fHeight; 1016 1017 switch (fOptions->keypad_mode) { 1018 case KEYPAD_MODE_COMPACT: 1019 { 1020 if (window->Bounds() == Frame()) { 1021 window->SetSizeLimits(kMinimumWidthCompact, 1022 kMaximumWidthCompact, kMinimumHeightCompact, 1023 kMaximumHeightCompact); 1024 window->ResizeTo(width, height * kDisplayScaleY); 1025 } else 1026 ResizeTo(width, height * kDisplayScaleY); 1027 1028 break; 1029 } 1030 1031 case KEYPAD_MODE_SCIENTIFIC: 1032 { 1033 fKeypadDescription = kKeypadDescriptionScientific; 1034 fRows = 8; 1035 _ParseCalcDesc(fKeypadDescription); 1036 1037 window->SetSizeLimits(kMinimumWidthScientific, 1038 kMaximumWidthScientific, kMinimumHeightScientific, 1039 kMaximumHeightScientific); 1040 1041 if (width < kMinimumWidthScientific) 1042 width = kMinimumWidthScientific; 1043 else if (width > kMaximumWidthScientific) 1044 width = kMaximumWidthScientific; 1045 1046 if (height < kMinimumHeightScientific) 1047 height = kMinimumHeightScientific; 1048 else if (height > kMaximumHeightScientific) 1049 height = kMaximumHeightScientific; 1050 1051 if (width != fWidth || height != fHeight) 1052 ResizeTo(width, height); 1053 else 1054 Invalidate(); 1055 1056 break; 1057 } 1058 1059 case KEYPAD_MODE_BASIC: 1060 default: 1061 { 1062 fKeypadDescription = kKeypadDescriptionBasic; 1063 fRows = 4; 1064 _ParseCalcDesc(fKeypadDescription); 1065 1066 window->SetSizeLimits(kMinimumWidthBasic, kMaximumWidthBasic, 1067 kMinimumHeightBasic, kMaximumHeightBasic); 1068 1069 if (width < kMinimumWidthBasic) 1070 width = kMinimumWidthBasic; 1071 else if (width > kMaximumWidthBasic) 1072 width = kMaximumWidthBasic; 1073 1074 if (height < kMinimumHeightBasic) 1075 height = kMinimumHeightBasic; 1076 else if (height > kMaximumHeightBasic) 1077 height = kMaximumHeightBasic; 1078 1079 if (width != fWidth || height != fHeight) 1080 ResizeTo(width, height); 1081 else 1082 Invalidate(); 1083 } 1084 } 1085 } 1086 1087 1088 // #pragma mark - 1089 1090 1091 /*static*/ status_t 1092 CalcView::_EvaluateThread(void* data) 1093 { 1094 CalcView* calcView = reinterpret_cast<CalcView*>(data); 1095 if (calcView == NULL) 1096 return B_BAD_TYPE; 1097 1098 BMessenger messenger(calcView); 1099 if (!messenger.IsValid()) 1100 return B_BAD_VALUE; 1101 1102 BString result; 1103 status_t status = acquire_sem(calcView->fEvaluateSemaphore); 1104 if (status == B_OK) { 1105 BLocale locale; 1106 BNumberFormat format(&locale); 1107 1108 ExpressionParser parser; 1109 parser.SetDegreeMode(calcView->fOptions->degree_mode); 1110 parser.SetSeparators(format.GetSeparator(B_DECIMAL_SEPARATOR), 1111 format.GetSeparator(B_GROUPING_SEPARATOR)); 1112 1113 BString expression(calcView->fExpressionTextView->Text()); 1114 try { 1115 result = parser.Evaluate(expression.String()); 1116 } catch (ParseException& e) { 1117 result << e.message.String() << " at " << (e.position + 1); 1118 status = B_ERROR; 1119 } 1120 release_sem(calcView->fEvaluateSemaphore); 1121 } else 1122 result = strerror(status); 1123 1124 BMessage message(kMsgDoneEvaluating); 1125 message.AddString(status == B_OK ? "value" : "error", result.String()); 1126 messenger.SendMessage(&message); 1127 1128 return status; 1129 } 1130 1131 1132 void 1133 CalcView::_Init(BMessage* settings) 1134 { 1135 // create expression text view 1136 fExpressionTextView = new ExpressionTextView(_ExpressionRect(), this); 1137 AddChild(fExpressionTextView); 1138 1139 // read data from archive 1140 _LoadSettings(settings); 1141 1142 // fetch the calc icon for compact view 1143 _FetchAppIcon(fCalcIcon); 1144 1145 fEvaluateSemaphore = create_sem(1, "Evaluate Semaphore"); 1146 } 1147 1148 1149 status_t 1150 CalcView::_LoadSettings(BMessage* archive) 1151 { 1152 if (!archive) 1153 return B_BAD_VALUE; 1154 1155 // record calculator description 1156 BString calcDesc; 1157 archive->FindString("calcDesc", &calcDesc); 1158 if (calcDesc == "scientific" || calcDesc.StartsWith("ln")) 1159 fKeypadDescription = kKeypadDescriptionScientific; 1160 else 1161 fKeypadDescription = kKeypadDescriptionBasic; 1162 1163 // read grid dimensions 1164 if (archive->FindInt16("cols", &fColumns) < B_OK) 1165 fColumns = 5; 1166 if (archive->FindInt16("rows", &fRows) < B_OK) 1167 fRows = 4; 1168 1169 // read color scheme 1170 const rgb_color* color; 1171 ssize_t size; 1172 if (archive->FindData("rgbBaseColor", B_RGB_COLOR_TYPE, 1173 (const void**)&color, &size) < B_OK 1174 || size != sizeof(rgb_color)) { 1175 fBaseColor = ui_color(B_PANEL_BACKGROUND_COLOR); 1176 puts("Missing rgbBaseColor from CalcView archive!\n"); 1177 } else 1178 fBaseColor = *color; 1179 1180 fHasCustomBaseColor = fBaseColor != ui_color(B_PANEL_BACKGROUND_COLOR); 1181 1182 // load options 1183 fOptions->LoadSettings(archive); 1184 1185 // load display text 1186 const char* display; 1187 if (archive->FindString("displayText", &display) < B_OK) { 1188 puts("Missing expression text from CalcView archive.\n"); 1189 } else { 1190 // init expression text 1191 fExpressionTextView->SetText(display); 1192 } 1193 1194 // load expression history 1195 fExpressionTextView->LoadSettings(archive); 1196 1197 // parse calculator description 1198 _ParseCalcDesc(fKeypadDescription); 1199 1200 // colorize based on base color. 1201 _Colorize(); 1202 1203 return B_OK; 1204 } 1205 1206 1207 void 1208 CalcView::_ParseCalcDesc(const char** keypadDescription) 1209 { 1210 // TODO: should calculate dimensions from desc here! 1211 fKeypad = new CalcKey[fRows * fColumns]; 1212 1213 // scan through calculator description and assemble keypad 1214 CalcKey* key = fKeypad; 1215 for (int i = 0; const char* p = keypadDescription[i]; i++) { 1216 // Move to next row as needed 1217 if (strcmp(p, "\n") == 0) 1218 continue; 1219 1220 // copy label 1221 strlcpy(key->label, B_TRANSLATE_NOCOLLECT(p), sizeof(key->label)); 1222 1223 // set code 1224 if (strcmp(p, "=") == 0) 1225 strlcpy(key->code, "\n", sizeof(key->code)); 1226 else 1227 strlcpy(key->code, p, sizeof(key->code)); 1228 1229 // set keymap 1230 if (strlen(key->label) == 1) 1231 strlcpy(key->keymap, key->label, sizeof(key->keymap)); 1232 else 1233 *key->keymap = '\0'; 1234 1235 key->flags = 0; 1236 1237 // add this to the expression text view, so that it 1238 // will forward the respective KeyDown event to us 1239 fExpressionTextView->AddKeypadLabel(key->label); 1240 1241 // advance 1242 key++; 1243 } 1244 } 1245 1246 1247 void 1248 CalcView::_PressKey(int key) 1249 { 1250 if (!fEnabled) 1251 return; 1252 1253 assert(key < (fRows * fColumns)); 1254 assert(key >= 0); 1255 1256 if (strcmp(fKeypad[key].code, "BS") == 0) { 1257 // BS means backspace 1258 fExpressionTextView->BackSpace(); 1259 } else if (strcmp(fKeypad[key].code, "C") == 0) { 1260 // C means clear 1261 fExpressionTextView->Clear(); 1262 } else if (strcmp(fKeypad[key].code, "acos") == 0 1263 || strcmp(fKeypad[key].code, "asin") == 0 1264 || strcmp(fKeypad[key].code, "atan") == 0 1265 || strcmp(fKeypad[key].code, "cbrt") == 0 1266 || strcmp(fKeypad[key].code, "ceil") == 0 1267 || strcmp(fKeypad[key].code, "cos") == 0 1268 || strcmp(fKeypad[key].code, "cosh") == 0 1269 || strcmp(fKeypad[key].code, "exp") == 0 1270 || strcmp(fKeypad[key].code, "floor") == 0 1271 || strcmp(fKeypad[key].code, "log") == 0 1272 || strcmp(fKeypad[key].code, "ln") == 0 1273 || strcmp(fKeypad[key].code, "sin") == 0 1274 || strcmp(fKeypad[key].code, "sinh") == 0 1275 || strcmp(fKeypad[key].code, "sqrt") == 0 1276 || strcmp(fKeypad[key].code, "tan") == 0 1277 || strcmp(fKeypad[key].code, "tanh") == 0) { 1278 int32 labelLen = strlen(fKeypad[key].code); 1279 int32 startSelection = 0; 1280 int32 endSelection = 0; 1281 fExpressionTextView->GetSelection(&startSelection, &endSelection); 1282 if (endSelection > startSelection) { 1283 // There is selected text, put it inbetween the parens 1284 fExpressionTextView->Insert(startSelection, fKeypad[key].code, 1285 labelLen); 1286 fExpressionTextView->Insert(startSelection + labelLen, "(", 1); 1287 fExpressionTextView->Insert(endSelection + labelLen + 1, ")", 1); 1288 // Put the cursor after the ending paren 1289 // Need to cast to BTextView because Select() is protected 1290 // in the InputTextView class 1291 static_cast<BTextView*>(fExpressionTextView)->Select( 1292 endSelection + labelLen + 2, endSelection + labelLen + 2); 1293 } else { 1294 // There is no selected text, insert at the cursor location 1295 fExpressionTextView->Insert(fKeypad[key].code); 1296 fExpressionTextView->Insert("()"); 1297 // Put the cursor inside the parens so you can enter an argument 1298 // Need to cast to BTextView because Select() is protected 1299 // in the InputTextView class 1300 static_cast<BTextView*>(fExpressionTextView)->Select( 1301 endSelection + labelLen + 1, endSelection + labelLen + 1); 1302 } 1303 } else if (strcmp(fKeypad[key].code, ".") == 0) { 1304 BLocale locale; 1305 BNumberFormat format(&locale); 1306 1307 fExpressionTextView->Insert(format.GetSeparator(B_DECIMAL_SEPARATOR)); 1308 } else { 1309 // check for evaluation order 1310 if (fKeypad[key].code[0] == '\n') { 1311 fExpressionTextView->ApplyChanges(); 1312 } else { 1313 // insert into expression text 1314 fExpressionTextView->Insert(fKeypad[key].code); 1315 } 1316 } 1317 } 1318 1319 1320 void 1321 CalcView::_PressKey(const char* label) 1322 { 1323 int32 key = _KeyForLabel(label); 1324 if (key >= 0) 1325 _PressKey(key); 1326 } 1327 1328 1329 int32 1330 CalcView::_KeyForLabel(const char* label) const 1331 { 1332 int keys = fRows * fColumns; 1333 for (int i = 0; i < keys; i++) { 1334 if (strcmp(fKeypad[i].label, label) == 0) { 1335 return i; 1336 } 1337 } 1338 return -1; 1339 } 1340 1341 1342 void 1343 CalcView::_FlashKey(int32 key, uint32 flashFlags) 1344 { 1345 if (fOptions->keypad_mode == KEYPAD_MODE_COMPACT) 1346 return; 1347 1348 if (flashFlags != 0) 1349 fKeypad[key].flags |= flashFlags; 1350 else 1351 fKeypad[key].flags = 0; 1352 Invalidate(); 1353 1354 if (fKeypad[key].flags == FLAGS_FLASH_KEY) { 1355 BMessage message(MSG_UNFLASH_KEY); 1356 message.AddInt32("key", key); 1357 BMessageRunner::StartSending(BMessenger(this), &message, 1358 kFlashOnOffInterval, 1); 1359 } 1360 } 1361 1362 1363 void 1364 CalcView::_Colorize() 1365 { 1366 rgb_color panelColor = ui_color(B_PANEL_TEXT_COLOR); 1367 if (rgb_color::Contrast(fBaseColor, panelColor) > 100) 1368 fButtonTextColor = panelColor; 1369 else { 1370 if (fBaseColor.IsLight()) 1371 fButtonTextColor = (rgb_color){ 0, 0, 0, 255 }; 1372 else 1373 fButtonTextColor = (rgb_color){ 255, 255, 255, 255 }; 1374 } 1375 } 1376 1377 1378 void 1379 CalcView::_CreatePopUpMenu(bool addKeypadModeMenuItems) 1380 { 1381 // construct items 1382 fAutoNumlockItem = new BMenuItem(B_TRANSLATE("Enable Num Lock on startup"), 1383 new BMessage(MSG_OPTIONS_AUTO_NUM_LOCK)); 1384 fAngleModeRadianItem = new BMenuItem(B_TRANSLATE("Radians"), 1385 new BMessage(MSG_OPTIONS_ANGLE_MODE_RADIAN)); 1386 fAngleModeDegreeItem = new BMenuItem(B_TRANSLATE("Degrees"), 1387 new BMessage(MSG_OPTIONS_ANGLE_MODE_DEGREE)); 1388 if (addKeypadModeMenuItems) { 1389 fKeypadModeCompactItem = new BMenuItem(B_TRANSLATE("Compact"), 1390 new BMessage(MSG_OPTIONS_KEYPAD_MODE_COMPACT), '0'); 1391 fKeypadModeBasicItem = new BMenuItem(B_TRANSLATE("Basic"), 1392 new BMessage(MSG_OPTIONS_KEYPAD_MODE_BASIC), '1'); 1393 fKeypadModeScientificItem = new BMenuItem(B_TRANSLATE("Scientific"), 1394 new BMessage(MSG_OPTIONS_KEYPAD_MODE_SCIENTIFIC), '2'); 1395 } 1396 1397 // apply current settings 1398 fAutoNumlockItem->SetMarked(fOptions->auto_num_lock); 1399 fAngleModeRadianItem->SetMarked(!fOptions->degree_mode); 1400 fAngleModeDegreeItem->SetMarked(fOptions->degree_mode); 1401 1402 // construct menu 1403 fPopUpMenu = new BPopUpMenu("pop-up", false, false); 1404 1405 fPopUpMenu->AddItem(fAutoNumlockItem); 1406 fPopUpMenu->AddSeparatorItem(); 1407 fPopUpMenu->AddItem(fAngleModeRadianItem); 1408 fPopUpMenu->AddItem(fAngleModeDegreeItem); 1409 if (addKeypadModeMenuItems) { 1410 fPopUpMenu->AddSeparatorItem(); 1411 fPopUpMenu->AddItem(fKeypadModeCompactItem); 1412 fPopUpMenu->AddItem(fKeypadModeBasicItem); 1413 fPopUpMenu->AddItem(fKeypadModeScientificItem); 1414 _MarkKeypadItems(fOptions->keypad_mode); 1415 } 1416 } 1417 1418 1419 BRect 1420 CalcView::_ExpressionRect() const 1421 { 1422 BRect r(0.0, 0.0, fWidth, fHeight); 1423 if (fOptions->keypad_mode != KEYPAD_MODE_COMPACT) { 1424 r.bottom = floorf(fHeight * kDisplayScaleY) + 1; 1425 } 1426 return r; 1427 } 1428 1429 1430 BRect 1431 CalcView::_KeypadRect() const 1432 { 1433 BRect r(0.0, 0.0, -1.0, -1.0); 1434 if (fOptions->keypad_mode != KEYPAD_MODE_COMPACT) { 1435 r.right = fWidth; 1436 r.bottom = fHeight; 1437 r.top = floorf(fHeight * kDisplayScaleY); 1438 } 1439 return r; 1440 } 1441 1442 1443 void 1444 CalcView::_MarkKeypadItems(uint8 keypad_mode) 1445 { 1446 switch (keypad_mode) { 1447 case KEYPAD_MODE_COMPACT: 1448 fKeypadModeCompactItem->SetMarked(true); 1449 fKeypadModeBasicItem->SetMarked(false); 1450 fKeypadModeScientificItem->SetMarked(false); 1451 break; 1452 1453 case KEYPAD_MODE_SCIENTIFIC: 1454 fKeypadModeCompactItem->SetMarked(false); 1455 fKeypadModeBasicItem->SetMarked(false); 1456 fKeypadModeScientificItem->SetMarked(true); 1457 break; 1458 1459 default: // KEYPAD_MODE_BASIC is the default 1460 fKeypadModeCompactItem->SetMarked(false); 1461 fKeypadModeBasicItem->SetMarked(true); 1462 fKeypadModeScientificItem->SetMarked(false); 1463 } 1464 } 1465 1466 1467 void 1468 CalcView::_FetchAppIcon(BBitmap* into) 1469 { 1470 entry_ref appRef; 1471 status_t status = be_roster->FindApp(kSignature, &appRef); 1472 if (status == B_OK) { 1473 BFile file(&appRef, B_READ_ONLY); 1474 BAppFileInfo appInfo(&file); 1475 status = appInfo.GetIcon(into, B_MINI_ICON); 1476 } 1477 if (status != B_OK) 1478 memset(into->Bits(), 0, into->BitsLength()); 1479 } 1480 1481 1482 // Returns whether or not CalcView is embedded somewhere, most likely 1483 // the Desktop 1484 bool 1485 CalcView::_IsEmbedded() 1486 { 1487 return Parent() != NULL && (Parent()->Flags() & B_DRAW_ON_CHILDREN) != 0; 1488 } 1489 1490 1491 void 1492 CalcView::_SetEnabled(bool enable) 1493 { 1494 fEnabled = enable; 1495 fExpressionTextView->MakeSelectable(enable); 1496 fExpressionTextView->MakeEditable(enable); 1497 } 1498