/* * Copyright 2007-2010, Haiku. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Stefano Ceccherini (burton666@libero.it) * Ingo Weinhold (ingo_weinhold@gmx.de) */ /*! The SmartTabView class is a BTabView descendant that hides the tab bar as long as there is only a single tab. Furthermore, it provides a tab context menu, as well as allowing you to close buttons with the middle mouse button. */ #include "SmartTabView.h" #include #include #include #include #include #include #include #include #include #include #include #include "TermConst.h" #include "WindowIcon.h" // #pragma mark - SmartTabView SmartTabView::SmartTabView(BRect frame, const char* name, button_width width, uint32 resizingMode, uint32 flags) : BTabView(frame, name, width, resizingMode, flags), fInsets(0, 0, 0, 0), fScrollView(NULL), fListener(NULL) { // Resize the container view to fill the complete tab view for single-tab // mode. Later, when more than one tab is added, we shrink the container // view again. frame.OffsetTo(B_ORIGIN); ContainerView()->MoveTo(frame.LeftTop()); ContainerView()->ResizeTo(frame.Width(), frame.Height()); BRect buttonRect(frame); buttonRect.left = frame.right - be_control_look->GetScrollBarWidth(B_VERTICAL) + 1; buttonRect.bottom = frame.top + TabHeight() - 1; fFullScreenButton = new BBitmapButton(kWindowIconBits, kWindowIconWidth, kWindowIconHeight, kWindowIconFormat, new BMessage(FULLSCREEN)); fFullScreenButton->SetResizingMode(B_FOLLOW_TOP | B_FOLLOW_RIGHT); fFullScreenButton->MoveTo(buttonRect.LeftTop()); fFullScreenButton->ResizeTo(buttonRect.Width(), buttonRect.Height()); fFullScreenButton->Hide(); AddChild(fFullScreenButton); } SmartTabView::~SmartTabView() { } void SmartTabView::SetInsets(float left, float top, float right, float bottom) { fInsets.left = left; fInsets.top = top; fInsets.right = right; fInsets.bottom = bottom; } void SmartTabView::MouseDown(BPoint point) { bool handled = false; if (CountTabs() > 1) { int32 tabIndex = _ClickedTabIndex(point); int32 buttons = 0; int32 clickCount = 0; Window()->CurrentMessage()->FindInt32("buttons", &buttons); Window()->CurrentMessage()->FindInt32("clicks", &clickCount); if ((buttons & B_PRIMARY_MOUSE_BUTTON) != 0 && clickCount == 2) { if (fListener != NULL) fListener->TabDoubleClicked(this, point, tabIndex); } else if ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0) { if (fListener != NULL) fListener->TabRightClicked(this, point, tabIndex); handled = true; } else if ((buttons & B_TERTIARY_MOUSE_BUTTON) != 0) { if (fListener != NULL) fListener->TabMiddleClicked(this, point, tabIndex); handled = true; } } if (!handled) BTabView::MouseDown(point); } void SmartTabView::AttachedToWindow() { BTabView::AttachedToWindow(); } void SmartTabView::AllAttached() { BTabView::AllAttached(); } void SmartTabView::Select(int32 index) { BTabView::Select(index); BView *view = ViewForTab(index); if (view != NULL) { view->MoveTo(fInsets.LeftTop()); view->ResizeTo(ContainerView()->Bounds().Width() - fInsets.left - fInsets.right, ContainerView()->Bounds().Height() - fInsets.top - fInsets.bottom); } if (fListener != NULL) fListener->TabSelected(this, index); } void SmartTabView::AddTab(BView* target, BTab* tab) { if (target == NULL) return; BTabView::AddTab(target, tab); if (CountTabs() == 1) { // Call select on the tab, since // we're resizing the contained view // inside that function Select(0); } else if (CountTabs() == 2) { // Need to resize the view, since we're switching from "normal" // to tabbed mode ContainerView()->ResizeBy(0, -TabHeight()); ContainerView()->MoveBy(0, TabHeight()); fFullScreenButton->Show(); // Make sure the content size stays the same, but take special care // of full screen mode BScreen screen(Window()); if (Window()->DecoratorFrame().Height() + 2 * TabHeight() < screen.Frame().Height()) { if (Window()->Frame().bottom + TabHeight() > screen.Frame().bottom - 5) { Window()->MoveBy(0, -TabHeight()); } Window()->ResizeBy(0, TabHeight()); } // Adapt scroll bar if there is one if (fScrollView != NULL) { BScrollBar* bar = fScrollView->ScrollBar(B_VERTICAL); if (bar != NULL) { bar->ResizeBy(0, -1); bar->MoveBy(0, 1); } } SetBorder(B_NO_BORDER); } Invalidate(TabFrame(CountTabs() - 1).InsetByCopy(-2, -2)); } BTab* SmartTabView::RemoveTab(int32 index) { if (CountTabs() == 2) { // Hide the tab bar again by resizing the container view // Make sure the content size stays the same, but take special care // of full screen mode BScreen screen(Window()); if (Window()->DecoratorFrame().Height() + 2 * TabHeight() < screen.Frame().Height()) { if (Window()->Frame().bottom > screen.Frame().bottom - 5 - TabHeight()) { Window()->MoveBy(0, TabHeight()); } Window()->ResizeBy(0, -TabHeight()); } // Adapt scroll bar if there is one if (fScrollView != NULL) { BScrollBar* bar = fScrollView->ScrollBar(B_VERTICAL); if (bar != NULL) { bar->ResizeBy(0, 1); bar->MoveBy(0, -1); } } ContainerView()->MoveBy(0, -TabHeight()); ContainerView()->ResizeBy(0, TabHeight()); fFullScreenButton->Hide(); } return BTabView::RemoveTab(index); } void SmartTabView::MoveTab(int32 index, int32 newIndex) { // check the indexes int32 count = CountTabs(); if (index == newIndex || index < 0 || newIndex < 0 || index >= count || newIndex >= count) { return; } // Remove the tab from its position and add it to the end. Then cycle the // tabs starting after the new position (save the tab already moved) to the // end. BTab* tab = BTabView::RemoveTab(index); BTabView::AddTab(tab->View(), tab); for (int32 i = newIndex; i < count - 1; i++) { tab = BTabView::RemoveTab(newIndex); BTabView::AddTab(tab->View(), tab); } } BRect SmartTabView::DrawTabs() { if (CountTabs() > 1) return BTabView::DrawTabs(); return BRect(); } /*! If you have a vertical scroll view that overlaps with the menu bar, it will be resized automatically when the tabs are hidden/shown. */ void SmartTabView::SetScrollView(BScrollView* scrollView) { fScrollView = scrollView; } int32 SmartTabView::_ClickedTabIndex(const BPoint& point) { if (point.y <= TabHeight()) { for (int32 i = 0; i < CountTabs(); i++) { if (TabFrame(i).Contains(point)) return i; } } return -1; } // #pragma mark - Listener SmartTabView::Listener::~Listener() { } void SmartTabView::Listener::TabSelected(SmartTabView* tabView, int32 index) { } void SmartTabView::Listener::TabDoubleClicked(SmartTabView* tabView, BPoint point, int32 index) { } void SmartTabView::Listener::TabMiddleClicked(SmartTabView* tabView, BPoint point, int32 index) { } void SmartTabView::Listener::TabRightClicked(SmartTabView* tabView, BPoint point, int32 index) { }