1 /* 2 * Copyright (C) 2010 Rene Gollent <rene@gollent.com> 3 * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de> 4 * 5 * All rights reserved. Distributed under the terms of the MIT License. 6 */ 7 8 #include "TabManager.h" 9 10 #include <stdio.h> 11 12 #include <new> 13 14 #include <Application.h> 15 #include <AbstractLayoutItem.h> 16 #include <Bitmap.h> 17 #include <Button.h> 18 #include <CardLayout.h> 19 #include <ControlLook.h> 20 #include <Catalog.h> 21 #include <GroupView.h> 22 #include <MenuBar.h> 23 #include <MenuItem.h> 24 #include <PopUpMenu.h> 25 #include <Rect.h> 26 #include <SpaceLayoutItem.h> 27 #include <Window.h> 28 29 #include "TabContainerView.h" 30 #include "TabView.h" 31 32 33 #undef B_TRANSLATION_CONTEXT 34 #define B_TRANSLATION_CONTEXT "Tab Manager" 35 36 37 const static BString kEmptyString; 38 39 40 // #pragma mark - Helper classes 41 42 43 class TabButton : public BButton { 44 public: 45 TabButton(BMessage* message) 46 : BButton("", message) 47 { 48 } 49 50 virtual BSize MinSize() 51 { 52 return BSize(12, 12); 53 } 54 55 virtual BSize MaxSize() 56 { 57 return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED); 58 } 59 60 virtual BSize PreferredSize() 61 { 62 return MinSize(); 63 } 64 65 virtual void Draw(BRect updateRect) 66 { 67 BRect bounds(Bounds()); 68 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 69 uint32 flags = be_control_look->Flags(this); 70 uint32 borders = BControlLook::B_TOP_BORDER 71 | BControlLook::B_BOTTOM_BORDER; 72 be_control_look->DrawTabFrame(this, bounds, updateRect, base, 73 0, borders, B_NO_BORDER); 74 if (IsEnabled()) { 75 rgb_color button = tint_color(base, 1.07); 76 be_control_look->DrawButtonBackground(this, bounds, updateRect, 77 button, flags, 0); 78 } 79 80 BRect symbolRect(bounds); 81 symbolRect.left = (symbolRect.left + symbolRect.right) / 2 - 6; 82 symbolRect.top = (symbolRect.top + symbolRect.bottom) / 2 - 6; 83 symbolRect.right = symbolRect.left + 12; 84 symbolRect.bottom = symbolRect.top + 12; 85 DrawSymbol(symbolRect, updateRect, base); 86 } 87 88 virtual void DrawSymbol(BRect frame, const BRect& updateRect, 89 const rgb_color& base) 90 { 91 } 92 }; 93 94 95 class ScrollLeftTabButton : public TabButton { 96 public: 97 ScrollLeftTabButton(BMessage* message) 98 : TabButton(message) 99 { 100 } 101 102 virtual void DrawSymbol(BRect frame, const BRect& updateRect, 103 const rgb_color& base) 104 { 105 float tint = IsEnabled() ? B_DARKEN_4_TINT : B_DARKEN_1_TINT; 106 be_control_look->DrawArrowShape(this, frame, updateRect, 107 base, BControlLook::B_LEFT_ARROW, 0, tint); 108 } 109 }; 110 111 112 class ScrollRightTabButton : public TabButton { 113 public: 114 ScrollRightTabButton(BMessage* message) 115 : TabButton(message) 116 { 117 } 118 119 virtual void DrawSymbol(BRect frame, const BRect& updateRect, 120 const rgb_color& base) 121 { 122 frame.OffsetBy(1, 0); 123 float tint = IsEnabled() ? B_DARKEN_4_TINT : B_DARKEN_1_TINT; 124 be_control_look->DrawArrowShape(this, frame, updateRect, 125 base, BControlLook::B_RIGHT_ARROW, 0, tint); 126 } 127 }; 128 129 130 class NewTabButton : public TabButton { 131 public: 132 NewTabButton(BMessage* message) 133 : TabButton(message) 134 { 135 SetToolTip("New tab (Cmd-T)"); 136 } 137 138 virtual BSize MinSize() 139 { 140 return BSize(18, 12); 141 } 142 143 virtual void DrawSymbol(BRect frame, const BRect& updateRect, 144 const rgb_color& base) 145 { 146 SetHighColor(tint_color(base, B_DARKEN_4_TINT)); 147 float inset = 3; 148 frame.InsetBy(2, 2); 149 frame.top++; 150 frame.left++; 151 FillRoundRect(BRect(frame.left, frame.top + inset, 152 frame.right, frame.bottom - inset), 1, 1); 153 FillRoundRect(BRect(frame.left + inset, frame.top, 154 frame.right - inset, frame.bottom), 1, 1); 155 } 156 }; 157 158 159 class TabMenuTabButton : public TabButton { 160 public: 161 TabMenuTabButton(BMessage* message) 162 : TabButton(message) 163 , fCloseTime(0) 164 { 165 } 166 167 virtual BSize MinSize() 168 { 169 return BSize(18, 12); 170 } 171 172 virtual void DrawSymbol(BRect frame, const BRect& updateRect, 173 const rgb_color& base) 174 { 175 be_control_look->DrawArrowShape(this, frame, updateRect, 176 base, BControlLook::B_DOWN_ARROW, 0, B_DARKEN_4_TINT); 177 } 178 179 virtual void MouseDown(BPoint point) 180 { 181 // Don't reopen the menu if it's already open or freshly closed. 182 bigtime_t clickSpeed = 2000000; 183 get_click_speed(&clickSpeed); 184 bigtime_t clickTime = Window()->CurrentMessage()->FindInt64("when"); 185 if (!IsEnabled() || (Value() == B_CONTROL_ON) 186 || clickTime < fCloseTime + clickSpeed) { 187 return; 188 } 189 190 // Invoke must be called before setting B_CONTROL_ON 191 // for the button to stay "down" 192 Invoke(); 193 SetValue(B_CONTROL_ON); 194 } 195 196 virtual void MouseUp(BPoint point) 197 { 198 // Do nothing 199 } 200 201 void MenuClosed() 202 { 203 fCloseTime = system_time(); 204 SetValue(B_CONTROL_OFF); 205 } 206 207 private: 208 bigtime_t fCloseTime; 209 }; 210 211 212 enum { 213 MSG_SCROLL_TABS_LEFT = 'stlt', 214 MSG_SCROLL_TABS_RIGHT = 'strt', 215 MSG_OPEN_TAB_MENU = 'otmn' 216 }; 217 218 219 class TabContainerGroup : public BGroupView { 220 public: 221 TabContainerGroup(TabContainerView* tabContainerView) 222 : 223 BGroupView(B_HORIZONTAL, 0.0), 224 fTabContainerView(tabContainerView), 225 fScrollLeftTabButton(NULL), 226 fScrollRightTabButton(NULL), 227 fTabMenuButton(NULL) 228 { 229 } 230 231 virtual void AttachedToWindow() 232 { 233 if (fScrollLeftTabButton != NULL) 234 fScrollLeftTabButton->SetTarget(this); 235 if (fScrollRightTabButton != NULL) 236 fScrollRightTabButton->SetTarget(this); 237 if (fTabMenuButton != NULL) 238 fTabMenuButton->SetTarget(this); 239 } 240 241 virtual void MessageReceived(BMessage* message) 242 { 243 if (fTabContainerView == NULL) 244 return BGroupView::MessageReceived(message); 245 246 switch (message->what) { 247 case MSG_SCROLL_TABS_LEFT: 248 fTabContainerView->SetFirstVisibleTabIndex( 249 fTabContainerView->FirstVisibleTabIndex() - 1); 250 break; 251 252 case MSG_SCROLL_TABS_RIGHT: 253 fTabContainerView->SetFirstVisibleTabIndex( 254 fTabContainerView->FirstVisibleTabIndex() + 1); 255 break; 256 257 case MSG_OPEN_TAB_MENU: 258 { 259 BPopUpMenu* tabMenu = new BPopUpMenu("tab menu", true, false); 260 int tabCount = fTabContainerView->GetLayout()->CountItems(); 261 for (int i = 0; i < tabCount; i++) { 262 TabView* tab = fTabContainerView->TabAt(i); 263 if (tab != NULL) { 264 BMenuItem* item = new(std::nothrow) 265 BMenuItem(tab->Label(), NULL); 266 if (item != NULL) { 267 tabMenu->AddItem(item); 268 if (i == fTabContainerView->SelectedTabIndex()) 269 item->SetMarked(true); 270 } 271 } 272 } 273 274 // Force layout to get the final menu size. InvalidateLayout() 275 // did not seem to work here. 276 tabMenu->AttachedToWindow(); 277 BRect buttonFrame = fTabMenuButton->Frame(); 278 BRect menuFrame = tabMenu->Frame(); 279 BPoint openPoint = ConvertToScreen(buttonFrame.LeftBottom()); 280 // Open with the right side of the menu aligned with the right 281 // side of the button and a little below. 282 openPoint.x -= menuFrame.Width() - buttonFrame.Width(); 283 openPoint.y += 2; 284 285 BMenuItem *selected = tabMenu->Go(openPoint, false, false, 286 ConvertToScreen(buttonFrame)); 287 if (selected) { 288 selected->SetMarked(true); 289 int32 index = tabMenu->IndexOf(selected); 290 if (index != B_ERROR) 291 fTabContainerView->SelectTab(index); 292 } 293 fTabMenuButton->MenuClosed(); 294 delete tabMenu; 295 296 break; 297 } 298 299 default: 300 BGroupView::MessageReceived(message); 301 break; 302 } 303 } 304 305 void AddScrollLeftButton(TabButton* button) 306 { 307 fScrollLeftTabButton = button; 308 GroupLayout()->AddView(button, 0.0f); 309 } 310 311 void AddScrollRightButton(TabButton* button) 312 { 313 fScrollRightTabButton = button; 314 GroupLayout()->AddView(button, 0.0f); 315 } 316 317 void AddTabMenuButton(TabMenuTabButton* button) 318 { 319 fTabMenuButton = button; 320 GroupLayout()->AddView(button, 0.0f); 321 } 322 323 void EnableScrollButtons(bool canScrollLeft, bool canScrollRight) 324 { 325 fScrollLeftTabButton->SetEnabled(canScrollLeft); 326 fScrollRightTabButton->SetEnabled(canScrollRight); 327 if (!canScrollLeft && !canScrollRight) { 328 // hide scroll buttons 329 } else { 330 // show scroll buttons 331 } 332 } 333 334 private: 335 TabContainerView* fTabContainerView; 336 TabButton* fScrollLeftTabButton; 337 TabButton* fScrollRightTabButton; 338 TabMenuTabButton* fTabMenuButton; 339 }; 340 341 342 class TabButtonContainer : public BGroupView { 343 public: 344 TabButtonContainer() 345 : 346 BGroupView(B_HORIZONTAL, 0.0) 347 { 348 SetFlags(Flags() | B_WILL_DRAW); 349 SetViewColor(B_TRANSPARENT_COLOR); 350 SetLowUIColor(B_PANEL_BACKGROUND_COLOR); 351 GroupLayout()->SetInsets(0, 6, 0, 0); 352 } 353 354 virtual void Draw(BRect updateRect) 355 { 356 // draw nothing 357 } 358 }; 359 360 361 class TabManagerController : public TabContainerView::Controller { 362 public: 363 TabManagerController(TabManager* manager); 364 365 virtual ~TabManagerController(); 366 367 virtual void UpdateSelection(int32 index) 368 { 369 fManager->SelectTab(index); 370 } 371 372 virtual bool HasFrames() 373 { 374 return false; 375 } 376 377 virtual TabView* CreateTabView(); 378 379 virtual void DoubleClickOutsideTabs(); 380 381 virtual void UpdateTabScrollability(bool canScrollLeft, 382 bool canScrollRight) 383 { 384 fTabContainerGroup->EnableScrollButtons(canScrollLeft, canScrollRight); 385 } 386 387 virtual void SetToolTip(const BString& text) 388 { 389 if (fCurrentToolTip == text) 390 return; 391 392 fCurrentToolTip = text; 393 fManager->GetTabContainerView()->HideToolTip(); 394 fManager->GetTabContainerView()->SetToolTip( 395 reinterpret_cast<BToolTip*>(NULL)); 396 fManager->GetTabContainerView()->SetToolTip(fCurrentToolTip.String()); 397 } 398 399 void CloseTab(int32 index); 400 401 void SetCloseButtonsAvailable(bool available) 402 { 403 fCloseButtonsAvailable = available; 404 } 405 406 bool CloseButtonsAvailable() const 407 { 408 return fCloseButtonsAvailable; 409 } 410 411 void SetDoubleClickOutsideTabsMessage(const BMessage& message, 412 const BMessenger& target); 413 414 void SetTabContainerGroup(TabContainerGroup* tabContainerGroup) 415 { 416 fTabContainerGroup = tabContainerGroup; 417 } 418 419 private: 420 TabManager* fManager; 421 TabContainerGroup* fTabContainerGroup; 422 bool fCloseButtonsAvailable; 423 BMessage* fDoubleClickOutsideTabsMessage; 424 BMessenger fTarget; 425 BString fCurrentToolTip; 426 }; 427 428 429 // #pragma mark - WebTabView 430 431 432 class WebTabView : public TabView { 433 public: 434 WebTabView(TabManagerController* controller); 435 ~WebTabView(); 436 437 virtual BSize MaxSize(); 438 439 virtual void DrawContents(BView* owner, BRect frame, 440 const BRect& updateRect); 441 442 virtual void MouseDown(BPoint where, uint32 buttons); 443 virtual void MouseUp(BPoint where); 444 virtual void MouseMoved(BPoint where, uint32 transit, 445 const BMessage* dragMessage); 446 447 void SetIcon(const BBitmap* icon); 448 449 private: 450 void _DrawCloseButton(BView* owner, BRect& frame, const BRect& updateRect); 451 BRect _CloseRectFrame(BRect frame) const; 452 453 private: 454 BBitmap* fIcon; 455 TabManagerController* fController; 456 bool fOverCloseRect; 457 bool fClicked; 458 }; 459 460 461 WebTabView::WebTabView(TabManagerController* controller) 462 : 463 TabView(), 464 fIcon(NULL), 465 fController(controller), 466 fOverCloseRect(false), 467 fClicked(false) 468 { 469 } 470 471 472 WebTabView::~WebTabView() 473 { 474 delete fIcon; 475 } 476 477 478 static const int kIconSize = 18; 479 static const int kIconInset = 3; 480 481 482 BSize 483 WebTabView::MaxSize() 484 { 485 // Account for icon. 486 BSize size(TabView::MaxSize()); 487 size.height = max_c(size.height, kIconSize + kIconInset * 2); 488 if (fIcon) 489 size.width += kIconSize + kIconInset * 2; 490 // Account for close button. 491 size.width += size.height; 492 return size; 493 } 494 495 496 void 497 WebTabView::DrawContents(BView* owner, BRect frame, const BRect& updateRect) 498 { 499 if (fController->CloseButtonsAvailable()) 500 _DrawCloseButton(owner, frame, updateRect); 501 502 if (fIcon != NULL) { 503 BRect iconBounds(0, 0, kIconSize - 1, kIconSize - 1); 504 // clip to icon bounds, if they are smaller 505 if (iconBounds.Contains(fIcon->Bounds())) 506 iconBounds = fIcon->Bounds(); 507 else { 508 // Try to scale down the icon by an even factor so the 509 // final size is between 14 and 18 pixel size. If this fails, 510 // the icon will simply be displayed at 18x18. 511 float scale = 2; 512 while ((fIcon->Bounds().Width() + 1) / scale > kIconSize) 513 scale *= 2; 514 if ((fIcon->Bounds().Width() + 1) / scale >= kIconSize - 4 515 && (fIcon->Bounds().Height() + 1) / scale >= kIconSize - 4 516 && (fIcon->Bounds().Height() + 1) / scale <= kIconSize) { 517 iconBounds.right = (fIcon->Bounds().Width() + 1) / scale - 1; 518 iconBounds.bottom = (fIcon->Bounds().Height() + 1) / scale - 1; 519 } 520 } 521 // account for borders 522 frame.top -= 2.0f; 523 BPoint iconPos(frame.left + kIconInset - 1, 524 frame.top + floorf((frame.Height() - iconBounds.Height()) / 2)); 525 iconBounds.OffsetTo(iconPos); 526 owner->SetDrawingMode(B_OP_ALPHA); 527 owner->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 528 owner->DrawBitmap(fIcon, fIcon->Bounds(), iconBounds, 529 B_FILTER_BITMAP_BILINEAR); 530 owner->SetDrawingMode(B_OP_COPY); 531 frame.left = frame.left + kIconSize + kIconInset * 2; 532 } 533 534 TabView::DrawContents(owner, frame, updateRect); 535 } 536 537 538 void 539 WebTabView::MouseDown(BPoint where, uint32 buttons) 540 { 541 if (buttons & B_TERTIARY_MOUSE_BUTTON) { 542 // Immediately close tab 543 fController->CloseTab(ContainerView()->IndexOf(this)); 544 return; 545 } 546 547 BRect closeRect = _CloseRectFrame(Frame()); 548 if (!fController->CloseButtonsAvailable() || !closeRect.Contains(where)) { 549 TabView::MouseDown(where, buttons); 550 return; 551 } 552 553 fClicked = true; 554 ContainerView()->Invalidate(closeRect); 555 } 556 557 558 void 559 WebTabView::MouseUp(BPoint where) 560 { 561 if (!fClicked) { 562 TabView::MouseUp(where); 563 return; 564 } 565 566 fClicked = false; 567 568 if (_CloseRectFrame(Frame()).Contains(where)) 569 fController->CloseTab(ContainerView()->IndexOf(this)); 570 } 571 572 573 void 574 WebTabView::MouseMoved(BPoint where, uint32 transit, 575 const BMessage* dragMessage) 576 { 577 BRect closeRect = _CloseRectFrame(Frame()); 578 bool overCloseRect = closeRect.Contains(where); 579 580 if (overCloseRect != fOverCloseRect 581 && fController->CloseButtonsAvailable()) { 582 fOverCloseRect = overCloseRect; 583 ContainerView()->Invalidate(closeRect); 584 } 585 586 // Set the tool tip 587 fController->SetToolTip(overCloseRect ? "" : Label()); 588 589 TabView::MouseMoved(where, transit, dragMessage); 590 } 591 592 593 void 594 WebTabView::SetIcon(const BBitmap* icon) 595 { 596 delete fIcon; 597 if (icon) 598 fIcon = new BBitmap(icon); 599 else 600 fIcon = NULL; 601 LayoutItem()->InvalidateLayout(); 602 } 603 604 605 BRect 606 WebTabView::_CloseRectFrame(BRect frame) const 607 { 608 frame.left = frame.right - frame.Height(); 609 return frame; 610 } 611 612 613 void 614 WebTabView::_DrawCloseButton(BView* owner, BRect& frame, 615 const BRect& updateRect) 616 { 617 BRect closeRect = _CloseRectFrame(frame); 618 frame.right = closeRect.left - be_control_look->DefaultLabelSpacing(); 619 620 closeRect.left = (closeRect.left + closeRect.right) / 2 - 3; 621 closeRect.right = closeRect.left + 6; 622 closeRect.top = (closeRect.top + closeRect.bottom) / 2 - 3; 623 closeRect.bottom = closeRect.top + 6; 624 625 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 626 float tint = B_DARKEN_1_TINT; 627 628 float isFront = ContainerView()->SelectedTab() 629 == static_cast<TabView*>(this); 630 if (!isFront) { 631 base = tint_color(base, tint); 632 tint *= 1.02; 633 } 634 635 if (fOverCloseRect) 636 tint *= 1.4; 637 else 638 tint *= 1.2; 639 640 if (fClicked && fOverCloseRect) { 641 // Draw the button frame 642 BRect buttonRect(closeRect.InsetByCopy(-4, -4)); 643 be_control_look->DrawButtonFrame(owner, buttonRect, updateRect, 644 base, base, 645 BControlLook::B_ACTIVATED | BControlLook::B_BLEND_FRAME); 646 be_control_look->DrawButtonBackground(owner, buttonRect, updateRect, 647 base, BControlLook::B_ACTIVATED); 648 closeRect.OffsetBy(1, 1); 649 tint *= 1.2; 650 } 651 652 // Draw the × 653 base = tint_color(base, tint); 654 owner->SetHighColor(base); 655 owner->SetPenSize(2); 656 owner->StrokeLine(closeRect.LeftTop(), closeRect.RightBottom()); 657 owner->StrokeLine(closeRect.LeftBottom(), closeRect.RightTop()); 658 owner->SetPenSize(1); 659 } 660 661 662 // #pragma mark - TabManagerController 663 664 665 TabManagerController::TabManagerController(TabManager* manager) 666 : 667 fManager(manager), 668 fTabContainerGroup(NULL), 669 fCloseButtonsAvailable(false), 670 fDoubleClickOutsideTabsMessage(NULL) 671 { 672 } 673 674 675 TabManagerController::~TabManagerController() 676 { 677 delete fDoubleClickOutsideTabsMessage; 678 } 679 680 681 TabView* 682 TabManagerController::CreateTabView() 683 { 684 return new WebTabView(this); 685 } 686 687 688 void 689 TabManagerController::DoubleClickOutsideTabs() 690 { 691 fTarget.SendMessage(fDoubleClickOutsideTabsMessage); 692 } 693 694 695 void 696 TabManagerController::CloseTab(int32 index) 697 { 698 fManager->CloseTab(index); 699 } 700 701 702 void 703 TabManagerController::SetDoubleClickOutsideTabsMessage(const BMessage& message, 704 const BMessenger& target) 705 { 706 delete fDoubleClickOutsideTabsMessage; 707 fDoubleClickOutsideTabsMessage = new BMessage(message); 708 fTarget = target; 709 } 710 711 712 // #pragma mark - TabManager 713 714 715 TabManager::TabManager(const BMessenger& target, BMessage* newTabMessage) 716 : 717 fController(new TabManagerController(this)), 718 fTarget(target) 719 { 720 fController->SetDoubleClickOutsideTabsMessage(*newTabMessage, 721 be_app_messenger); 722 723 fContainerView = new BView("web view container", 0); 724 fCardLayout = new BCardLayout(); 725 fContainerView->SetLayout(fCardLayout); 726 727 fTabContainerView = new TabContainerView(fController); 728 fTabContainerGroup = new TabContainerGroup(fTabContainerView); 729 fTabContainerGroup->GroupLayout()->SetInsets(0, 3, 0, 0); 730 731 fController->SetTabContainerGroup(fTabContainerGroup); 732 733 #if INTEGRATE_MENU_INTO_TAB_BAR 734 fMenuContainer = new BGroupView(B_HORIZONTAL, 0); 735 fMenuContainer->GroupLayout()->SetInsets(0, -3, 0, -3); 736 fTabContainerGroup->GroupLayout()->AddView(fMenuContainer, 0.0f); 737 #endif 738 739 fTabContainerGroup->GroupLayout()->AddView(fTabContainerView); 740 fTabContainerGroup->AddScrollLeftButton(new ScrollLeftTabButton( 741 new BMessage(MSG_SCROLL_TABS_LEFT))); 742 fTabContainerGroup->AddScrollRightButton(new ScrollRightTabButton( 743 new BMessage(MSG_SCROLL_TABS_RIGHT))); 744 NewTabButton* newTabButton = new NewTabButton(newTabMessage); 745 newTabButton->SetTarget(be_app); 746 fTabContainerGroup->GroupLayout()->AddView(newTabButton, 0.0f); 747 fTabContainerGroup->AddTabMenuButton(new TabMenuTabButton( 748 new BMessage(MSG_OPEN_TAB_MENU))); 749 } 750 751 752 TabManager::~TabManager() 753 { 754 delete fController; 755 } 756 757 758 void 759 TabManager::SetTarget(const BMessenger& target) 760 { 761 fTarget = target; 762 } 763 764 765 const BMessenger& 766 TabManager::Target() const 767 { 768 return fTarget; 769 } 770 771 772 #if INTEGRATE_MENU_INTO_TAB_BAR 773 BGroupLayout* 774 TabManager::MenuContainerLayout() const 775 { 776 return fMenuContainer->GroupLayout(); 777 } 778 #endif 779 780 781 BView* 782 TabManager::TabGroup() const 783 { 784 return fTabContainerGroup; 785 } 786 787 788 BView* 789 TabManager::GetTabContainerView() const 790 { 791 return fTabContainerView; 792 } 793 794 795 BView* 796 TabManager::ContainerView() const 797 { 798 return fContainerView; 799 } 800 801 802 BView* 803 TabManager::ViewForTab(int32 tabIndex) const 804 { 805 BLayoutItem* item = fCardLayout->ItemAt(tabIndex); 806 if (item != NULL) 807 return item->View(); 808 return NULL; 809 } 810 811 812 int32 813 TabManager::TabForView(const BView* containedView) const 814 { 815 int32 count = fCardLayout->CountItems(); 816 for (int32 i = 0; i < count; i++) { 817 BLayoutItem* item = fCardLayout->ItemAt(i); 818 if (item->View() == containedView) 819 return i; 820 } 821 return -1; 822 } 823 824 825 bool 826 TabManager::HasView(const BView* containedView) const 827 { 828 return TabForView(containedView) >= 0; 829 } 830 831 832 void 833 TabManager::SelectTab(int32 tabIndex) 834 { 835 fCardLayout->SetVisibleItem(tabIndex); 836 fTabContainerView->SelectTab(tabIndex); 837 838 BMessage message(TAB_CHANGED); 839 message.AddInt32("tab index", tabIndex); 840 fTarget.SendMessage(&message); 841 } 842 843 844 void 845 TabManager::SelectTab(const BView* containedView) 846 { 847 int32 tabIndex = TabForView(containedView); 848 if (tabIndex >= 0) 849 SelectTab(tabIndex); 850 } 851 852 853 int32 854 TabManager::SelectedTabIndex() const 855 { 856 return fCardLayout->VisibleIndex(); 857 } 858 859 860 void 861 TabManager::CloseTab(int32 tabIndex) 862 { 863 BMessage message(CLOSE_TAB); 864 message.AddInt32("tab index", tabIndex); 865 fTarget.SendMessage(&message); 866 } 867 868 869 void 870 TabManager::AddTab(BView* view, const char* label, int32 index) 871 { 872 fTabContainerView->AddTab(label, index); 873 fCardLayout->AddView(index, view); 874 } 875 876 877 BView* 878 TabManager::RemoveTab(int32 index) 879 { 880 // It's important to remove the view first, since 881 // removing the tab will preliminary mess with the selected tab 882 // and then item count of card layout and tab container will not 883 // match yet. 884 BLayoutItem* item = fCardLayout->RemoveItem(index); 885 if (item == NULL) 886 return NULL; 887 888 TabView* tab = fTabContainerView->RemoveTab(index); 889 delete tab; 890 891 BView* view = item->View(); 892 delete item; 893 return view; 894 } 895 896 897 int32 898 TabManager::CountTabs() const 899 { 900 return fCardLayout->CountItems(); 901 } 902 903 904 void 905 TabManager::SetTabLabel(int32 tabIndex, const char* label) 906 { 907 fTabContainerView->SetTabLabel(tabIndex, label); 908 } 909 910 const BString& 911 TabManager::TabLabel(int32 tabIndex) 912 { 913 TabView* tab = fTabContainerView->TabAt(tabIndex); 914 if (tab) 915 return tab->Label(); 916 else 917 return kEmptyString; 918 } 919 920 void 921 TabManager::SetTabIcon(const BView* containedView, const BBitmap* icon) 922 { 923 WebTabView* tab = dynamic_cast<WebTabView*>(fTabContainerView->TabAt( 924 TabForView(containedView))); 925 if (tab) 926 tab->SetIcon(icon); 927 } 928 929 930 void 931 TabManager::SetCloseButtonsAvailable(bool available) 932 { 933 if (available == fController->CloseButtonsAvailable()) 934 return; 935 fController->SetCloseButtonsAvailable(available); 936 fTabContainerView->Invalidate(); 937 } 938