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