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