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