2 * Copyright 2007-2010, Haiku. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Stefano Ceccherini (burton666@libero.it)
7 * Ingo Weinhold (ingo_weinhold@gmx.de)
11 /*! The SmartTabView class is a BTabView descendant that hides the tab bar
12 as long as there is only a single tab.
13 Furthermore, it provides a tab context menu, as well as allowing you to
14 close buttons with the middle mouse button.
18 #include "SmartTabView.h"
25 #include <Messenger.h>
27 #include <ScrollView.h>
31 // #pragma mark - SmartTabView
34 SmartTabView::SmartTabView(BRect frame
, const char* name
, button_width width
,
35 uint32 resizingMode
, uint32 flags
)
37 BTabView(frame
, name
, width
, resizingMode
, flags
),
42 // Resize the container view to fill the complete tab view for single-tab
43 // mode. Later, when more than one tab is added, we shrink the container
45 frame
.OffsetTo(B_ORIGIN
);
46 ContainerView()->MoveTo(frame
.LeftTop());
47 ContainerView()->ResizeTo(frame
.Width(), frame
.Height());
51 SmartTabView::~SmartTabView()
57 SmartTabView::SetInsets(float left
, float top
, float right
, float bottom
)
61 fInsets
.right
= right
;
62 fInsets
.bottom
= bottom
;
67 SmartTabView::MouseDown(BPoint point
)
71 if (CountTabs() > 1) {
72 int32 tabIndex
= _ClickedTabIndex(point
);
75 Window()->CurrentMessage()->FindInt32("buttons", &buttons
);
76 Window()->CurrentMessage()->FindInt32("clicks", &clickCount
);
78 if ((buttons
& B_PRIMARY_MOUSE_BUTTON
) != 0 && clickCount
== 2) {
79 if (fListener
!= NULL
)
80 fListener
->TabDoubleClicked(this, point
, tabIndex
);
81 } else if ((buttons
& B_SECONDARY_MOUSE_BUTTON
) != 0) {
82 if (fListener
!= NULL
)
83 fListener
->TabRightClicked(this, point
, tabIndex
);
85 } else if ((buttons
& B_TERTIARY_MOUSE_BUTTON
) != 0) {
86 if (fListener
!= NULL
)
87 fListener
->TabMiddleClicked(this, point
, tabIndex
);
93 BTabView::MouseDown(point
);
98 SmartTabView::AttachedToWindow()
100 BTabView::AttachedToWindow();
105 SmartTabView::AllAttached()
107 BTabView::AllAttached();
112 SmartTabView::Select(int32 index
)
114 BTabView::Select(index
);
115 BView
*view
= ViewForTab(index
);
117 view
->MoveTo(fInsets
.LeftTop());
118 view
->ResizeTo(ContainerView()->Bounds().Width()
119 - fInsets
.left
- fInsets
.right
,
120 ContainerView()->Bounds().Height() - fInsets
.top
- fInsets
.bottom
);
123 if (fListener
!= NULL
)
124 fListener
->TabSelected(this, index
);
129 SmartTabView::AddTab(BView
* target
, BTab
* tab
)
134 BTabView::AddTab(target
, tab
);
136 if (CountTabs() == 1) {
137 // Call select on the tab, since
138 // we're resizing the contained view
139 // inside that function
141 } else if (CountTabs() == 2) {
142 // Need to resize the view, since we're switching from "normal"
144 ContainerView()->ResizeBy(0, -TabHeight());
145 ContainerView()->MoveBy(0, TabHeight());
147 // Make sure the content size stays the same, but take special care
148 // of full screen mode
149 BScreen
screen(Window());
150 if (Window()->DecoratorFrame().Height() + 2 * TabHeight()
151 < screen
.Frame().Height()) {
152 if (Window()->Frame().bottom
+ TabHeight()
153 > screen
.Frame().bottom
- 5) {
154 Window()->MoveBy(0, -TabHeight());
157 Window()->ResizeBy(0, TabHeight());
160 // Adapt scroll bar if there is one
161 if (fScrollView
!= NULL
) {
162 BScrollBar
* bar
= fScrollView
->ScrollBar(B_VERTICAL
);
164 bar
->ResizeBy(0, -1);
169 SetBorder(B_NO_BORDER
);
172 Invalidate(TabFrame(CountTabs() - 1).InsetByCopy(-2, -2));
177 SmartTabView::RemoveTab(int32 index
)
179 if (CountTabs() == 2) {
180 // Hide the tab bar again by resizing the container view
182 // Make sure the content size stays the same, but take special care
183 // of full screen mode
184 BScreen
screen(Window());
185 if (Window()->DecoratorFrame().Height() + 2 * TabHeight()
186 < screen
.Frame().Height()) {
187 if (Window()->Frame().bottom
188 > screen
.Frame().bottom
- 5 - TabHeight()) {
189 Window()->MoveBy(0, TabHeight());
191 Window()->ResizeBy(0, -TabHeight());
194 // Adapt scroll bar if there is one
195 if (fScrollView
!= NULL
) {
196 BScrollBar
* bar
= fScrollView
->ScrollBar(B_VERTICAL
);
203 ContainerView()->MoveBy(0, -TabHeight());
204 ContainerView()->ResizeBy(0, TabHeight());
207 return BTabView::RemoveTab(index
);
212 SmartTabView::MoveTab(int32 index
, int32 newIndex
)
215 int32 count
= CountTabs();
216 if (index
== newIndex
|| index
< 0 || newIndex
< 0 || index
>= count
217 || newIndex
>= count
) {
221 // Remove the tab from its position and add it to the end. Then cycle the
222 // tabs starting after the new position (save the tab already moved) to the
224 BTab
* tab
= BTabView::RemoveTab(index
);
225 BTabView::AddTab(tab
->View(), tab
);
227 for (int32 i
= newIndex
; i
< count
- 1; i
++) {
228 tab
= BTabView::RemoveTab(newIndex
);
229 BTabView::AddTab(tab
->View(), tab
);
235 SmartTabView::DrawTabs()
238 return BTabView::DrawTabs();
244 /*! If you have a vertical scroll view that overlaps with the menu bar, it will
245 be resized automatically when the tabs are hidden/shown.
248 SmartTabView::SetScrollView(BScrollView
* scrollView
)
250 fScrollView
= scrollView
;
255 SmartTabView::_ClickedTabIndex(const BPoint
& point
)
257 if (point
.y
<= TabHeight()) {
258 for (int32 i
= 0; i
< CountTabs(); i
++) {
259 if (TabFrame(i
).Contains(point
))
268 // #pragma mark - Listener
271 SmartTabView::Listener::~Listener()
277 SmartTabView::Listener::TabSelected(SmartTabView
* tabView
, int32 index
)
283 SmartTabView::Listener::TabDoubleClicked(SmartTabView
* tabView
, BPoint point
,
290 SmartTabView::Listener::TabMiddleClicked(SmartTabView
* tabView
, BPoint point
,
297 SmartTabView::Listener::TabRightClicked(SmartTabView
* tabView
, BPoint point
,