haiku/src/apps/terminal/SmartTabView.cpp

320 lines
6.9 KiB
C++

/*
* 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 <stdio.h>
#include <BitmapButton.h>
#include <Button.h>
#include <Catalog.h>
#include <Locale.h>
#include <Message.h>
#include <Messenger.h>
#include <Screen.h>
#include <ScrollView.h>
#include <Window.h>
#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 - B_V_SCROLL_BAR_WIDTH + 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)
{
}