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