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