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 627 float tint; 628 if (base.IsLight()) 629 tint = B_DARKEN_1_TINT; 630 else 631 tint = 0.50; 632 633 float isFront = ContainerView()->SelectedTab() == static_cast<TabView*>(this); 634 635 if (base.IsLight()){ 636 if (!isFront) { 637 base = tint_color(base, tint); 638 tint *= 1.02; 639 } 640 641 if (fOverCloseRect) 642 tint *= 1.4; 643 else 644 tint *= 1.2; 645 } else { 646 if (!isFront) { 647 base = tint_color(base, tint); 648 tint *= 0.80; 649 } 650 651 if (fOverCloseRect) 652 tint *= 0.6; 653 else 654 tint *= 0.9; 655 } 656 657 if (fClicked && fOverCloseRect) { 658 // Draw the button frame 659 BRect buttonRect(closeRect.InsetByCopy(-4, -4)); 660 be_control_look->DrawButtonFrame(owner, buttonRect, updateRect, 661 base, base, 662 BControlLook::B_ACTIVATED | BControlLook::B_BLEND_FRAME); 663 be_control_look->DrawButtonBackground(owner, buttonRect, updateRect, 664 base, BControlLook::B_ACTIVATED); 665 closeRect.OffsetBy(1, 1); 666 tint *= 1.2; 667 } 668 669 // Draw the × 670 base = tint_color(base, tint); 671 owner->SetHighColor(base); 672 owner->SetPenSize(2); 673 owner->StrokeLine(closeRect.LeftTop(), closeRect.RightBottom()); 674 owner->StrokeLine(closeRect.LeftBottom(), closeRect.RightTop()); 675 owner->SetPenSize(1); 676 } 677 678 679 // #pragma mark - TabManagerController 680 681 682 TabManagerController::TabManagerController(TabManager* manager) 683 : 684 fManager(manager), 685 fTabContainerGroup(NULL), 686 fCloseButtonsAvailable(false), 687 fDoubleClickOutsideTabsMessage(NULL) 688 { 689 } 690 691 692 TabManagerController::~TabManagerController() 693 { 694 delete fDoubleClickOutsideTabsMessage; 695 } 696 697 698 TabView* 699 TabManagerController::CreateTabView() 700 { 701 return new WebTabView(this); 702 } 703 704 705 void 706 TabManagerController::DoubleClickOutsideTabs() 707 { 708 fTarget.SendMessage(fDoubleClickOutsideTabsMessage); 709 } 710 711 712 void 713 TabManagerController::CloseTab(int32 index) 714 { 715 fManager->CloseTab(index); 716 } 717 718 719 void 720 TabManagerController::SetDoubleClickOutsideTabsMessage(const BMessage& message, 721 const BMessenger& target) 722 { 723 delete fDoubleClickOutsideTabsMessage; 724 fDoubleClickOutsideTabsMessage = new BMessage(message); 725 fTarget = target; 726 } 727 728 729 // #pragma mark - TabManager 730 731 732 TabManager::TabManager(const BMessenger& target, BMessage* newTabMessage) 733 : 734 fController(new TabManagerController(this)), 735 fTarget(target) 736 { 737 fController->SetDoubleClickOutsideTabsMessage(*newTabMessage, 738 be_app_messenger); 739 740 fContainerView = new BView("web view container", 0); 741 fCardLayout = new BCardLayout(); 742 fContainerView->SetLayout(fCardLayout); 743 744 fTabContainerView = new TabContainerView(fController); 745 fTabContainerGroup = new TabContainerGroup(fTabContainerView); 746 fTabContainerGroup->GroupLayout()->SetInsets(0, 3, 0, 0); 747 748 fController->SetTabContainerGroup(fTabContainerGroup); 749 750 #if INTEGRATE_MENU_INTO_TAB_BAR 751 fMenuContainer = new BGroupView(B_HORIZONTAL, 0); 752 fMenuContainer->GroupLayout()->SetInsets(0, -3, 0, -3); 753 fTabContainerGroup->GroupLayout()->AddView(fMenuContainer, 0.0f); 754 #endif 755 756 fTabContainerGroup->GroupLayout()->AddView(fTabContainerView); 757 fTabContainerGroup->AddScrollLeftButton(new ScrollLeftTabButton( 758 new BMessage(MSG_SCROLL_TABS_LEFT))); 759 fTabContainerGroup->AddScrollRightButton(new ScrollRightTabButton( 760 new BMessage(MSG_SCROLL_TABS_RIGHT))); 761 NewTabButton* newTabButton = new NewTabButton(newTabMessage); 762 newTabButton->SetTarget(be_app); 763 fTabContainerGroup->GroupLayout()->AddView(newTabButton, 0.0f); 764 fTabContainerGroup->AddTabMenuButton(new TabMenuTabButton( 765 new BMessage(MSG_OPEN_TAB_MENU))); 766 } 767 768 769 TabManager::~TabManager() 770 { 771 delete fController; 772 } 773 774 775 void 776 TabManager::SetTarget(const BMessenger& target) 777 { 778 fTarget = target; 779 } 780 781 782 const BMessenger& 783 TabManager::Target() const 784 { 785 return fTarget; 786 } 787 788 789 #if INTEGRATE_MENU_INTO_TAB_BAR 790 BGroupLayout* 791 TabManager::MenuContainerLayout() const 792 { 793 return fMenuContainer->GroupLayout(); 794 } 795 #endif 796 797 798 BView* 799 TabManager::TabGroup() const 800 { 801 return fTabContainerGroup; 802 } 803 804 805 BView* 806 TabManager::GetTabContainerView() const 807 { 808 return fTabContainerView; 809 } 810 811 812 BView* 813 TabManager::ContainerView() const 814 { 815 return fContainerView; 816 } 817 818 819 BView* 820 TabManager::ViewForTab(int32 tabIndex) const 821 { 822 BLayoutItem* item = fCardLayout->ItemAt(tabIndex); 823 if (item != NULL) 824 return item->View(); 825 return NULL; 826 } 827 828 829 int32 830 TabManager::TabForView(const BView* containedView) const 831 { 832 int32 count = fCardLayout->CountItems(); 833 for (int32 i = 0; i < count; i++) { 834 BLayoutItem* item = fCardLayout->ItemAt(i); 835 if (item->View() == containedView) 836 return i; 837 } 838 return -1; 839 } 840 841 842 bool 843 TabManager::HasView(const BView* containedView) const 844 { 845 return TabForView(containedView) >= 0; 846 } 847 848 849 void 850 TabManager::SelectTab(int32 tabIndex) 851 { 852 fCardLayout->SetVisibleItem(tabIndex); 853 fTabContainerView->SelectTab(tabIndex); 854 855 BMessage message(TAB_CHANGED); 856 message.AddInt32("tab index", tabIndex); 857 fTarget.SendMessage(&message); 858 } 859 860 861 void 862 TabManager::SelectTab(const BView* containedView) 863 { 864 int32 tabIndex = TabForView(containedView); 865 if (tabIndex >= 0) 866 SelectTab(tabIndex); 867 } 868 869 870 int32 871 TabManager::SelectedTabIndex() const 872 { 873 return fCardLayout->VisibleIndex(); 874 } 875 876 877 void 878 TabManager::CloseTab(int32 tabIndex) 879 { 880 BMessage message(CLOSE_TAB); 881 message.AddInt32("tab index", tabIndex); 882 fTarget.SendMessage(&message); 883 } 884 885 886 void 887 TabManager::AddTab(BView* view, const char* label, int32 index) 888 { 889 fTabContainerView->AddTab(label, index); 890 fCardLayout->AddView(index, view); 891 } 892 893 894 BView* 895 TabManager::RemoveTab(int32 index) 896 { 897 // It's important to remove the view first, since 898 // removing the tab will preliminary mess with the selected tab 899 // and then item count of card layout and tab container will not 900 // match yet. 901 BLayoutItem* item = fCardLayout->RemoveItem(index); 902 if (item == NULL) 903 return NULL; 904 905 TabView* tab = fTabContainerView->RemoveTab(index); 906 delete tab; 907 908 BView* view = item->View(); 909 delete item; 910 return view; 911 } 912 913 914 int32 915 TabManager::CountTabs() const 916 { 917 return fCardLayout->CountItems(); 918 } 919 920 921 void 922 TabManager::SetTabLabel(int32 tabIndex, const char* label) 923 { 924 fTabContainerView->SetTabLabel(tabIndex, label); 925 } 926 927 const BString& 928 TabManager::TabLabel(int32 tabIndex) 929 { 930 TabView* tab = fTabContainerView->TabAt(tabIndex); 931 if (tab) 932 return tab->Label(); 933 else 934 return kEmptyString; 935 } 936 937 void 938 TabManager::SetTabIcon(const BView* containedView, const BBitmap* icon) 939 { 940 WebTabView* tab = dynamic_cast<WebTabView*>(fTabContainerView->TabAt( 941 TabForView(containedView))); 942 if (tab) 943 tab->SetIcon(icon); 944 } 945 946 947 void 948 TabManager::SetCloseButtonsAvailable(bool available) 949 { 950 if (available == fController->CloseButtonsAvailable()) 951 return; 952 fController->SetCloseButtonsAvailable(available); 953 fTabContainerView->Invalidate(); 954 } 955