1 //------------------------------------------------------------------------------ 2 // Copyright (c) 2001-2002, OpenBeOS 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a 5 // copy of this software and associated documentation files (the "Software"), 6 // to deal in the Software without restriction, including without limitation 7 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 // and/or sell copies of the Software, and to permit persons to whom the 9 // Software is furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 // DEALINGS IN THE SOFTWARE. 21 // 22 // File Name: Alert.cpp 23 // Author: Erik Jaesler (erik@cgsoftware.com) 24 // Description: BAlert displays a modal alert window. 25 //------------------------------------------------------------------------------ 26 27 // Standard Includes ----------------------------------------------------------- 28 #include <string.h> 29 30 // System Includes ------------------------------------------------------------- 31 #include <Invoker.h> 32 #include <Looper.h> 33 #include <Message.h> 34 #include <MessageFilter.h> 35 36 #include <Alert.h> 37 #include <Bitmap.h> 38 #include <Button.h> 39 // TODO: Fix 40 // This is hacked in because something in Accelerant.h or SupportDefs.h is lame! 41 typedef unsigned int uint; 42 #include <Screen.h> 43 #include <TextView.h> 44 #include <View.h> 45 46 #include <File.h> 47 #include <FindDirectory.h> 48 #include <Path.h> 49 #include <Resources.h> 50 51 #include <Autolock.h> 52 53 // Project Includes ------------------------------------------------------------ 54 55 // Local Includes -------------------------------------------------------------- 56 57 // Local Defines --------------------------------------------------------------- 58 #define DEFAULT_RECT BRect(100, 100, 100, 100) 59 #define max(LHS, RHS) ((LHS) > (RHS) ? (LHS) : (RHS)) 60 61 // Globals --------------------------------------------------------------------- 62 const unsigned int kAlertButtonMsg = 'ALTB'; 63 const int kSemTimeOut = 50000; 64 65 const int kButtonBottomOffset = 9; 66 const int kDefButtonBottomOffset = 6; 67 const int kButtonRightOffset = 6; 68 const int kButtonSpaceOffset = 6; 69 const int kButtonOffsetSpaceOffset = 26; 70 const int kButtonLeftOffset = 62; 71 const int kButtonUsualWidth = 75; 72 73 const int kWindowIconOffset = 27; 74 const int kWindowMinWidth = 310; 75 const int kWindowMinOffset = 12; 76 const int kWindowOffsetMinWidth = 335; 77 78 const int kIconStripeWidth = 30; 79 80 const int kTextLeftOffset = 10; 81 const int kTextIconOffset = kWindowIconOffset + kIconStripeWidth - 2; 82 const int kTextTopOffset = 6; 83 const int kTextRightOffset = 10; 84 const int kTextBottomOffset = 45; 85 86 //------------------------------------------------------------------------------ 87 class TAlertView : public BView 88 { 89 public: 90 TAlertView(BRect frame); 91 TAlertView(BMessage* archive); 92 ~TAlertView(); 93 94 static TAlertView* Instantiate(BMessage* archive); 95 status_t Archive(BMessage* archive, bool deep = true); 96 97 virtual void Draw(BRect updateRect); 98 99 // These functions (or something analogous) are missing from libbe.so's 100 // dump. I can only assume that the bitmap is a public var in the 101 // original implementation -- or BAlert is a friend of TAlertView. 102 // Neither one is necessary, since I can just add these. 103 void SetBitmap(BBitmap* Icon) { fIconBitmap = Icon; } 104 BBitmap* Bitmap() { return fIconBitmap; } 105 106 private: 107 BBitmap* fIconBitmap; 108 }; 109 //------------------------------------------------------------------------------ 110 // I'm making a guess based on the name and TextEntryAlert's implementation that 111 // this is a BMessageFilter. I'm not sure, but I think I actually prefer how 112 // TextEntryAlert does it, but there are clearly no message filtering functions 113 // on BAlert so here we go. 114 class _BAlertFilter_ : public BMessageFilter 115 { 116 public: 117 _BAlertFilter_(BAlert* Alert); 118 ~_BAlertFilter_(); 119 120 virtual filter_result Filter(BMessage* msg, BHandler** target); 121 122 private: 123 BAlert* fAlert; 124 }; 125 //------------------------------------------------------------------------------ 126 127 128 //------------------------------------------------------------------------------ 129 BAlert::BAlert(const char *title, const char *text, const char *button1, 130 const char *button2, const char *button3, button_width width, 131 alert_type type) 132 : BWindow(DEFAULT_RECT, title, B_MODAL_WINDOW, 133 B_NOT_CLOSABLE | B_NOT_RESIZABLE) 134 { 135 InitObject(text, button1, button2, button3, width, B_EVEN_SPACING, type); 136 } 137 //------------------------------------------------------------------------------ 138 BAlert::BAlert(const char *title, const char *text, const char *button1, 139 const char *button2, const char *button3, button_width width, 140 button_spacing spacing, alert_type type) 141 : BWindow(DEFAULT_RECT, title, B_MODAL_WINDOW, 142 B_NOT_CLOSABLE | B_NOT_RESIZABLE) 143 { 144 InitObject(text, button1, button2, button3, width, spacing, type); 145 } 146 //------------------------------------------------------------------------------ 147 BAlert::~BAlert() 148 { 149 // Probably not necessary, but it makes me feel better. 150 if (fAlertSem >= B_OK) 151 { 152 delete_sem(fAlertSem); 153 } 154 } 155 //------------------------------------------------------------------------------ 156 BAlert::BAlert(BMessage* data) 157 : BWindow(data) 158 { 159 BAutolock Autolock(this); 160 if (Autolock.IsLocked()) 161 { 162 fInvoker = NULL; 163 fAlertSem = -1; 164 fAlertVal = -1; 165 166 fTextView = (BTextView*)FindView("_tv_"); 167 168 fButtons[0] = (BButton*)FindView("_b0_"); 169 fButtons[1] = (BButton*)FindView("_b1_"); 170 fButtons[2] = (BButton*)FindView("_b2_"); 171 172 if (fButtons[2]) 173 SetDefaultButton(fButtons[2]); 174 else if (fButtons[1]) 175 SetDefaultButton(fButtons[1]); 176 else if (fButtons[0]) 177 SetDefaultButton(fButtons[0]); 178 179 TAlertView* Master = (TAlertView*)FindView("_master_"); 180 if (Master) 181 { 182 Master->SetBitmap(InitIcon()); 183 } 184 185 // Get keys 186 char key; 187 for (int32 i = 0; i < 3; ++i) 188 { 189 if (data->FindInt8("_but_key", i, (int8*)&key) == B_OK) 190 fKeys[i] = key; 191 } 192 193 int32 temp; 194 // Get alert type 195 if (data->FindInt32("_atype", &temp) == B_OK) 196 fMsgType = (alert_type)temp; 197 198 // Get button width 199 if (data->FindInt32("_but_width", &temp) == B_OK) 200 fButtonWidth = (button_width)temp; 201 202 AddCommonFilter(new _BAlertFilter_(this)); 203 } 204 } 205 //------------------------------------------------------------------------------ 206 BArchivable* BAlert::Instantiate(BMessage* data) 207 { 208 if (!validate_instantiation(data, "BAlert")) 209 { 210 return NULL; 211 } 212 213 return new BAlert(data); 214 } 215 //------------------------------------------------------------------------------ 216 status_t BAlert::Archive(BMessage* data, bool deep) const 217 { 218 BWindow::Archive(data, deep); 219 220 // Stow the text 221 data->AddString("_text", fTextView->Text()); 222 223 // Stow the alert type 224 data->AddInt32("_atype", fMsgType); 225 226 // Stow the button width 227 data->AddInt32("_but_width", fButtonWidth); 228 229 // Stow the shortcut keys 230 if (fKeys[0] || fKeys[1] || fKeys[2]) 231 { 232 // If we have any to save, we must save something for everyone so it 233 // doesn't get confusing on the unarchive. 234 data->AddInt8("_but_key", fKeys[0]); 235 data->AddInt8("_but_key", fKeys[1]); 236 data->AddInt8("_but_key", fKeys[2]); 237 } 238 239 return B_OK; 240 } 241 //------------------------------------------------------------------------------ 242 void BAlert::SetShortcut(int32 index, char key) 243 { 244 if (index >= 0 && index < 3) 245 fKeys[index] = key; 246 } 247 //------------------------------------------------------------------------------ 248 char BAlert::Shortcut(int32 index) const 249 { 250 if (index >= 0 && index < 3) 251 return fKeys[index]; 252 253 return 0; 254 } 255 //------------------------------------------------------------------------------ 256 int32 BAlert::Go() 257 { 258 // TODO: Add sound? 259 fAlertSem = create_sem(0, "AlertSem"); 260 if (fAlertSem < B_OK) 261 { 262 Quit(); 263 return -1; 264 } 265 266 // Get the originating window, if it exists 267 BWindow* Window = 268 dynamic_cast<BWindow*>(BLooper::LooperForThread(find_thread(NULL))); 269 270 Show(); 271 272 // Heavily modified from TextEntryAlert code; the original didn't let the 273 // blocked window ever draw. 274 if (Window) 275 { 276 status_t err; 277 for (;;) 278 { 279 do 280 { 281 err = acquire_sem_etc(fAlertSem, 1, B_RELATIVE_TIMEOUT, 282 kSemTimeOut); 283 // We've (probably) had our time slice taken away from us 284 } while (err == B_INTERRUPTED); 285 if (err == B_BAD_SEM_ID) 286 { 287 // Semaphore was finally nuked in MessageReceived 288 break; 289 } 290 Window->UpdateIfNeeded(); 291 } 292 } 293 else 294 { 295 // No window to update, so just hang out until we're done. 296 while (acquire_sem(fAlertSem) == B_INTERRUPTED) 297 { 298 ; 299 } 300 } 301 302 // Have to cache the value since we delete on Quit() 303 int32 value = fAlertVal; 304 if (Lock()) 305 { 306 Quit(); 307 } 308 309 return value; 310 } 311 //------------------------------------------------------------------------------ 312 status_t BAlert::Go(BInvoker* invoker) 313 { 314 // TODO: Add sound? 315 // It would be cool if we triggered a system sound depending on the type of 316 // alert. 317 fInvoker = invoker; 318 Show(); 319 return B_OK; 320 } 321 //------------------------------------------------------------------------------ 322 void BAlert::MessageReceived(BMessage* msg) 323 { 324 if (msg->what == kAlertButtonMsg) 325 { 326 int32 which; 327 if (msg->FindInt32("which", &which) == B_OK) 328 { 329 if (fAlertSem < B_OK) 330 { 331 // Semaphore hasn't been created; we're running asynchronous 332 if (fInvoker) 333 { 334 BMessage* out = fInvoker->Message(); 335 if (out && (out->AddInt32("which", which) == B_OK || 336 out->ReplaceInt32("which", which) == B_OK)) 337 { 338 fInvoker->Invoke(); 339 } 340 } 341 } 342 else 343 { 344 // Created semaphore means were running synchronously 345 fAlertVal = which; 346 347 // TextAlertVar does release_sem() below, and then sets the 348 // member var. That doesn't make much sense to me, since we 349 // want to be able to clean up at some point. Better to just 350 // nuke the semaphore now; we don't need it any more and this 351 // lets synchronous Go() continue just as well. 352 delete_sem(fAlertSem); 353 fAlertSem = -1; 354 } 355 } 356 } 357 } 358 //------------------------------------------------------------------------------ 359 void BAlert::FrameResized(float new_width, float new_height) 360 { 361 // Nothing in documentation; will have to test 362 // TODO: Implement? 363 BWindow::FrameResized(new_width, new_height); 364 } 365 //------------------------------------------------------------------------------ 366 BButton* BAlert::ButtonAt(int32 index) const 367 { 368 BButton* Button = NULL; 369 if (index >= 0 && index < 3) 370 Button = fButtons[index]; 371 372 return Button; 373 } 374 //------------------------------------------------------------------------------ 375 BTextView* BAlert::TextView() const 376 { 377 return fTextView; 378 } 379 //------------------------------------------------------------------------------ 380 BHandler* BAlert::ResolveSpecifier(BMessage* msg, int32 index, 381 BMessage* specifier, int32 form, 382 const char* property) 383 { 384 // Nothing in documentation; will have to test 385 // TODO: Implement? 386 return BWindow::ResolveSpecifier(msg, index, specifier, form, property); 387 } 388 //------------------------------------------------------------------------------ 389 status_t BAlert::GetSupportedSuites(BMessage* data) 390 { 391 // Nothing in documentation; will have to test 392 // TODO: Implement? 393 return BWindow::GetSupportedSuites(data); 394 } 395 //------------------------------------------------------------------------------ 396 void BAlert::DispatchMessage(BMessage* msg, BHandler* handler) 397 { 398 // Nothing in documentation; will have to test 399 // TODO: Implement? 400 BWindow::DispatchMessage(msg, handler); 401 } 402 //------------------------------------------------------------------------------ 403 void BAlert::Quit() 404 { 405 // Nothing in documentation; will have to test 406 // TODO: Implement? 407 BWindow::Quit(); 408 } 409 //------------------------------------------------------------------------------ 410 bool BAlert::QuitRequested() 411 { 412 // Nothing in documentation; will have to test 413 // TODO: Implement? 414 return BWindow::QuitRequested(); 415 } 416 //------------------------------------------------------------------------------ 417 BPoint BAlert::AlertPosition(float width, float height) 418 { 419 BPoint result(100, 100); 420 421 BWindow* Window = 422 dynamic_cast<BWindow*>(BLooper::LooperForThread(find_thread(NULL))); 423 424 BScreen Screen(Window); 425 if (!Screen.IsValid()) 426 { 427 // ... then we're in deep trouble 428 // But what to say about it? 429 // debugger(???); 430 } 431 432 BRect screenRect = Screen.Frame(); 433 434 // Horizontally, we're smack in the middle 435 result.x = (screenRect.Width() / 2.0) - (width / 2.0); 436 437 // This is probably sooo wrong, but it looks right on 1024 x 768 438 result.y = (screenRect.Height() / 4.0) - ceil(height / 3.0); 439 440 return result; 441 } 442 //------------------------------------------------------------------------------ 443 status_t BAlert::Perform(perform_code d, void* arg) 444 { 445 return BWindow::Perform(d, arg); 446 } 447 //------------------------------------------------------------------------------ 448 void BAlert::_ReservedAlert1() 449 { 450 ; 451 } 452 //------------------------------------------------------------------------------ 453 void BAlert::_ReservedAlert2() 454 { 455 ; 456 } 457 //------------------------------------------------------------------------------ 458 void BAlert::_ReservedAlert3() 459 { 460 ; 461 } 462 //------------------------------------------------------------------------------ 463 void BAlert::InitObject(const char* text, const char* button0, 464 const char* button1, const char* button2, 465 button_width width, button_spacing spacing, 466 alert_type type) 467 { 468 BAutolock Autolock(this); 469 if (Autolock.IsLocked()) 470 { 471 fInvoker = NULL; 472 fAlertSem = -1; 473 fAlertVal = -1; 474 fButtons[0] = fButtons[1] = fButtons[2] = NULL; 475 fTextView = NULL; 476 fKeys[0] = fKeys[1] = fKeys[2] = 0; 477 fMsgType = type; 478 fButtonWidth = width; 479 480 // Set up the "_master_" view 481 TAlertView* MasterView = new TAlertView(Bounds()); 482 MasterView->SetBitmap(InitIcon()); 483 AddChild(MasterView); 484 485 // Set up the buttons 486 int buttonCount = 0; 487 488 // Have to have at least one button 489 if (button0 == NULL) 490 { 491 debugger("BAlert's must have at least one button."); 492 button0 = ""; 493 } 494 495 BMessage ProtoMsg(kAlertButtonMsg); 496 ProtoMsg.AddInt32("which", 0); 497 fButtons[0] = new BButton(BRect(0, 0, 0, 0), "_b0_", button0, 498 new BMessage(ProtoMsg), 499 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); 500 ++buttonCount; 501 502 if (button1) 503 { 504 ProtoMsg.ReplaceInt32("which", 1); 505 fButtons[buttonCount] = new BButton(BRect(0, 0, 0, 0), "_b1_", button1, 506 new BMessage(ProtoMsg), 507 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); 508 ++buttonCount; 509 } 510 511 if (button2) 512 { 513 ProtoMsg.ReplaceInt32("which", 2); 514 fButtons[buttonCount] = new BButton(BRect(0, 0, 0, 0), "_b2_", button2, 515 new BMessage(ProtoMsg), 516 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); 517 ++buttonCount; 518 } 519 520 SetDefaultButton(fButtons[buttonCount - 1]); 521 522 float buttonWidth = 0; 523 float buttonHeight = 0; 524 for (int i = 0; i < buttonCount; ++i) 525 { 526 float temp; 527 fButtons[i]->GetPreferredSize(&temp, &buttonHeight); 528 buttonWidth = max(buttonWidth, temp); 529 } 530 531 // Add first, because the buttons will ResizeToPreferred() 532 // in AttachedToWindow() 533 for (int i = 0; i < buttonCount; ++i) 534 { 535 MasterView->AddChild(fButtons[i]); 536 } 537 538 for (int i = buttonCount - 1; i >= 0; --i) 539 { 540 switch (fButtonWidth) 541 { 542 case B_WIDTH_FROM_WIDEST: 543 fButtons[i]->ResizeTo(buttonWidth, buttonHeight); 544 break; 545 546 case B_WIDTH_FROM_LABEL: 547 fButtons[i]->ResizeToPreferred(); 548 break; 549 550 default: // B_WIDTH_AS_USUAL 551 fButtons[i]->GetPreferredSize(&buttonWidth, &buttonHeight); 552 buttonWidth = max(buttonWidth, kButtonUsualWidth); 553 fButtons[i]->ResizeTo(buttonWidth, buttonHeight); 554 break; 555 } 556 557 float buttonX; 558 float buttonY; 559 float temp; 560 561 fButtons[i]->GetPreferredSize(&temp, &buttonHeight); 562 buttonY = Bounds().bottom - buttonHeight; 563 564 if (i == buttonCount - 1) // the right-most button 565 { 566 buttonX = Bounds().right - fButtons[i]->Frame().Width() - 567 kButtonRightOffset; 568 buttonY -= kDefButtonBottomOffset; 569 } 570 else 571 { 572 buttonX = fButtons[i + 1]->Frame().left - 573 fButtons[i]->Frame().Width() - 574 kButtonSpaceOffset; 575 576 if (i == 0) 577 { 578 if (spacing == B_OFFSET_SPACING) 579 { 580 buttonX -= kButtonOffsetSpaceOffset; 581 } 582 else if (buttonCount == 3) 583 { 584 buttonX -= 3; 585 } 586 } 587 buttonY -= kButtonBottomOffset; 588 } 589 590 fButtons[i]->MoveTo(buttonX, buttonY); 591 } 592 593 594 // Resize the window, if necessary 595 float totalWidth = kButtonRightOffset; 596 totalWidth += fButtons[buttonCount - 1]->Frame().right - 597 fButtons[0]->Frame().left; 598 if (MasterView->Bitmap()) 599 { 600 totalWidth += kIconStripeWidth + kWindowIconOffset; 601 } 602 else 603 { 604 totalWidth += kWindowMinOffset; 605 } 606 607 if (spacing == B_OFFSET_SPACING) 608 { 609 totalWidth = max(kWindowOffsetMinWidth, totalWidth); 610 } 611 else 612 { 613 totalWidth += 5; 614 totalWidth = max(kWindowMinWidth, totalWidth); 615 } 616 ResizeTo(totalWidth, Bounds().Height()); 617 618 // Set up the text view 619 BRect TextViewRect(kTextLeftOffset, kTextTopOffset, 620 Bounds().right - kTextRightOffset, 621 Bounds().bottom - kTextBottomOffset); 622 if (MasterView->Bitmap()) 623 { 624 TextViewRect.left = kTextIconOffset; 625 } 626 627 fTextView = new BTextView(TextViewRect, "_tv_", 628 TextViewRect, 629 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW); 630 fTextView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 631 fTextView->SetText(text, strlen(text)); 632 fTextView->MakeEditable(false); 633 fTextView->MakeSelectable(false); 634 fTextView->SetWordWrap(true); 635 636 // Now resize the window vertically so that all the text is visible 637 float textHeight = fTextView->TextHeight(0, fTextView->CountLines()); 638 TextViewRect.OffsetTo(0, 0); 639 textHeight -= TextViewRect.Height(); 640 ResizeBy(0, textHeight); 641 fTextView->ResizeBy(0, textHeight); 642 TextViewRect.bottom += textHeight; 643 fTextView->SetTextRect(TextViewRect); 644 645 MasterView->AddChild(fTextView); 646 647 AddCommonFilter(new _BAlertFilter_(this)); 648 649 MoveTo(AlertPosition(Frame().Width(), Frame().Height())); 650 } 651 } 652 //------------------------------------------------------------------------------ 653 BBitmap* BAlert::InitIcon() 654 { 655 // After a bit of a search, I found the icons in app_server. =P 656 BBitmap* Icon = NULL; 657 BPath Path; 658 if (find_directory(B_BEOS_SERVERS_DIRECTORY, &Path) == B_OK) 659 { 660 Path.Append("app_server"); 661 BFile File; 662 if (File.SetTo(Path.Path(), B_READ_ONLY) == B_OK) 663 { 664 BResources Resources; 665 if (Resources.SetTo(&File) == B_OK) 666 { 667 // Which icon are we trying to load? 668 const char* iconName = ""; // Don't want any seg faults 669 switch (fMsgType) 670 { 671 case B_INFO_ALERT: 672 iconName = "info"; 673 break; 674 675 case B_IDEA_ALERT: 676 iconName = "idea"; 677 break; 678 679 case B_WARNING_ALERT: 680 iconName = "warn"; 681 break; 682 683 case B_STOP_ALERT: 684 iconName = "stop"; 685 break; 686 687 default: 688 // Alert type is either invalid or B_EMPTY_ALERT; 689 // either way, we're not going to load an icon 690 return Icon; 691 } 692 693 // Load the raw icon data 694 size_t size; 695 const void* rawIcon = 696 Resources.LoadResource('ICON', iconName, &size); 697 698 if (rawIcon) 699 { 700 // Now build the bitmap 701 Icon = new BBitmap(BRect(0, 0, 31, 31), B_CMAP8); 702 Icon->SetBits(rawIcon, size, 0, B_CMAP8); 703 } 704 } 705 } 706 } 707 708 if (!Icon) 709 { 710 // If there's no icon, it's an empty alert indeed. 711 fMsgType = B_EMPTY_ALERT; 712 } 713 714 return Icon; 715 } 716 //------------------------------------------------------------------------------ 717 718 719 //------------------------------------------------------------------------------ 720 // #pragma mark - 721 // #pragma mark TAlertView 722 // #pragma mark - 723 //------------------------------------------------------------------------------ 724 TAlertView::TAlertView(BRect frame) 725 : BView(frame, "TAlertView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW), 726 fIconBitmap(NULL) 727 { 728 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 729 } 730 //------------------------------------------------------------------------------ 731 TAlertView::TAlertView(BMessage* archive) 732 : BView(archive), 733 fIconBitmap(NULL) 734 { 735 } 736 //------------------------------------------------------------------------------ 737 TAlertView::~TAlertView() 738 { 739 if (fIconBitmap) 740 { 741 delete fIconBitmap; 742 } 743 } 744 //------------------------------------------------------------------------------ 745 TAlertView* TAlertView::Instantiate(BMessage* archive) 746 { 747 if (!validate_instantiation(archive, "TAlertView")) 748 { 749 return NULL; 750 } 751 752 return new TAlertView(archive); 753 } 754 //------------------------------------------------------------------------------ 755 status_t TAlertView::Archive(BMessage* archive, bool deep) 756 { 757 return BView::Archive(archive, deep); 758 } 759 //------------------------------------------------------------------------------ 760 void TAlertView::Draw(BRect updateRect) 761 { 762 // Here's the fun stuff 763 if (fIconBitmap) 764 { 765 BRect StripeRect = Bounds(); 766 StripeRect.right = kIconStripeWidth; 767 SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); 768 FillRect(StripeRect); 769 770 SetDrawingMode(B_OP_OVER); 771 DrawBitmapAsync(fIconBitmap, BPoint(18, 6)); 772 SetDrawingMode(B_OP_COPY); 773 } 774 } 775 //------------------------------------------------------------------------------ 776 777 778 //------------------------------------------------------------------------------ 779 // #pragma mark - 780 // #pragma mark _BAlertFilter_ 781 // #pragma mark - 782 //------------------------------------------------------------------------------ 783 _BAlertFilter_::_BAlertFilter_(BAlert* Alert) 784 : BMessageFilter(B_KEY_DOWN), 785 fAlert(Alert) 786 { 787 } 788 //------------------------------------------------------------------------------ 789 _BAlertFilter_::~_BAlertFilter_() 790 { 791 ; 792 } 793 //------------------------------------------------------------------------------ 794 filter_result _BAlertFilter_::Filter(BMessage* msg, BHandler** target) 795 { 796 if (msg->what == B_KEY_DOWN) 797 { 798 char byte; 799 if (msg->FindInt8("byte", (int8*)&byte) == B_OK) 800 { 801 for (int i = 0; i < 3; ++i) 802 { 803 if (byte == fAlert->Shortcut(i) && fAlert->ButtonAt(i)) 804 { 805 char space = ' '; 806 fAlert->ButtonAt(i)->KeyDown(&space, 1); 807 808 return B_SKIP_MESSAGE; 809 } 810 } 811 } 812 } 813 814 return B_DISPATCH_MESSAGE; 815 } 816 //------------------------------------------------------------------------------ 817 818 /* 819 * $Log $ 820 * 821 * $Id $ 822 * 823 */ 824 825