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