2 * Copyright 2001-2015 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Marc Flerackers (mflerackers@androme.be)
7 * Jérôme Duval (korli@users.berlios.de)
8 * Stephan Aßmus <superstippi@gmx.de>
10 * Rene Gollent (rene@gollent.com)
15 #include <TabViewPrivate.h>
22 #include <CardLayout.h>
23 #include <ControlLook.h>
24 #include <GroupLayout.h>
25 #include <LayoutUtils.h>
28 #include <PropertyInfo.h>
33 #include <binary_compatibility/Support.h>
36 static property_info sPropertyList
[] = {
39 { B_GET_PROPERTY
, B_SET_PROPERTY
},
40 { B_DIRECT_SPECIFIER
},
49 BTab::BTab(BView
* contentsView
)
60 BTab::BTab(BMessage
* archive
)
70 if (archive
->FindBool("_disable", &disable
) != B_OK
)
90 BTab::Instantiate(BMessage
* archive
)
92 if (validate_instantiation(archive
, "BTab"))
93 return new BTab(archive
);
100 BTab::Archive(BMessage
* data
, bool deep
) const
102 status_t result
= BArchivable::Archive(data
, deep
);
107 result
= data
->AddBool("_disable", false);
114 BTab::Perform(uint32 d
, void* arg
)
116 return BArchivable::Perform(d
, arg
);
124 return fView
->Name();
131 BTab::SetLabel(const char* label
)
133 if (label
== NULL
|| fView
== NULL
)
136 fView
->SetName(label
);
138 if (fTabView
!= NULL
)
139 fTabView
->Invalidate();
144 BTab::IsSelected() const
151 BTab::Select(BView
* owner
)
155 if (owner
== NULL
|| fView
== NULL
)
158 // NOTE: Views are not added/removed, if there is layout,
159 // they are made visible/invisible in that case.
160 if (owner
->GetLayout() == NULL
&& fView
->Parent() == NULL
)
161 owner
->AddChild(fView
);
169 // NOTE: Views are not added/removed, if there is layout,
170 // they are made visible/invisible in that case.
171 bool removeView
= false;
172 BView
* container
= fView
->Parent();
173 if (container
!= NULL
)
175 dynamic_cast<BCardLayout
*>(container
->GetLayout()) == NULL
;
185 BTab::SetEnabled(bool enable
)
192 BTab::IsEnabled() const
199 BTab::MakeFocus(bool focus
)
206 BTab::IsFocus() const
213 BTab::SetView(BView
* view
)
215 if (view
== NULL
|| fView
== view
)
224 if (fTabView
!= NULL
&& fSelected
) {
225 Select(fTabView
->ContainerView());
226 fTabView
->Invalidate();
239 BTab::DrawFocusMark(BView
* owner
, BRect frame
)
241 float width
= owner
->StringWidth(Label());
243 owner
->SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR
));
245 float offset
= IsSelected() ? 3 : 2;
246 switch (fTabView
->TabSide()) {
247 case BTabView::kTopSide
:
248 owner
->StrokeLine(BPoint((frame
.left
+ frame
.right
- width
) / 2.0,
249 frame
.bottom
- offset
),
250 BPoint((frame
.left
+ frame
.right
+ width
) / 2.0,
251 frame
.bottom
- offset
));
253 case BTabView::kBottomSide
:
254 owner
->StrokeLine(BPoint((frame
.left
+ frame
.right
- width
) / 2.0,
256 BPoint((frame
.left
+ frame
.right
+ width
) / 2.0,
257 frame
.top
+ offset
));
259 case BTabView::kLeftSide
:
260 owner
->StrokeLine(BPoint(frame
.right
- offset
,
261 (frame
.top
+ frame
.bottom
- width
) / 2.0),
262 BPoint(frame
.right
- offset
,
263 (frame
.top
+ frame
.bottom
+ width
) / 2.0));
265 case BTabView::kRightSide
:
266 owner
->StrokeLine(BPoint(frame
.left
+ offset
,
267 (frame
.top
+ frame
.bottom
- width
) / 2.0),
268 BPoint(frame
.left
+ offset
,
269 (frame
.top
+ frame
.bottom
+ width
) / 2.0));
276 BTab::DrawLabel(BView
* owner
, BRect frame
)
278 float rotation
= 0.0f
;
279 BPoint
center(frame
.left
+ frame
.Width() / 2,
280 frame
.top
+ frame
.Height() / 2);
281 switch (fTabView
->TabSide()) {
282 case BTabView::kTopSide
:
283 case BTabView::kBottomSide
:
286 case BTabView::kLeftSide
:
289 case BTabView::kRightSide
:
294 if (rotation
!= 0.0f
) {
295 // DrawLabel doesn't allow rendering rotated text
296 // rotate frame first and BAffineTransform will handle the rotation
297 // we can't give "unrotated" frame because it comes from
298 // BTabView::TabFrame and it is also used to handle mouse clicks
299 BRect
originalFrame(frame
);
300 frame
.top
= center
.y
- originalFrame
.Width() / 2;
301 frame
.bottom
= center
.y
+ originalFrame
.Width() / 2;
302 frame
.left
= center
.x
- originalFrame
.Height() / 2;
303 frame
.right
= center
.x
+ originalFrame
.Height() / 2;
306 BAffineTransform transform
;
307 transform
.RotateBy(center
, rotation
* M_PI
/ 180.0f
);
308 owner
->SetTransform(transform
);
309 be_control_look
->DrawLabel(owner
, Label(), frame
, frame
,
310 ui_color(B_PANEL_BACKGROUND_COLOR
),
311 IsEnabled() ? 0 : BPrivate::BControlLook::B_DISABLED
,
312 BAlignment(B_ALIGN_HORIZONTAL_CENTER
, B_ALIGN_VERTICAL_CENTER
));
313 owner
->SetTransform(BAffineTransform());
318 BTab::DrawTab(BView
* owner
, BRect frame
, tab_position position
, bool full
)
320 rgb_color no_tint
= ui_color(B_PANEL_BACKGROUND_COLOR
);
322 if (fTabView
->TabSide() == BTabView::kTopSide
323 || fTabView
->TabSide() == BTabView::kBottomSide
) {
324 borders
= BControlLook::B_TOP_BORDER
| BControlLook::B_BOTTOM_BORDER
;
326 if (frame
.left
== owner
->Bounds().left
)
327 borders
|= BControlLook::B_LEFT_BORDER
;
329 if (frame
.right
== owner
->Bounds().right
)
330 borders
|= BControlLook::B_RIGHT_BORDER
;
331 } else if (fTabView
->TabSide() == BTabView::kLeftSide
332 || fTabView
->TabSide() == BTabView::kRightSide
) {
333 borders
= BControlLook::B_LEFT_BORDER
| BControlLook::B_RIGHT_BORDER
;
335 if (frame
.top
== owner
->Bounds().top
)
336 borders
|= BControlLook::B_TOP_BORDER
;
338 if (frame
.bottom
== owner
->Bounds().bottom
)
339 borders
|= BControlLook::B_BOTTOM_BORDER
;
342 if (position
== B_TAB_FRONT
) {
343 be_control_look
->DrawActiveTab(owner
, frame
, frame
, no_tint
, 0,
344 borders
, fTabView
->TabSide());
346 be_control_look
->DrawInactiveTab(owner
, frame
, frame
, no_tint
, 0,
347 borders
, fTabView
->TabSide());
350 DrawLabel(owner
, frame
);
354 // #pragma mark - FBC padding and private methods
357 void BTab::_ReservedTab1() {}
358 void BTab::_ReservedTab2() {}
359 void BTab::_ReservedTab3() {}
360 void BTab::_ReservedTab4() {}
361 void BTab::_ReservedTab5() {}
362 void BTab::_ReservedTab6() {}
363 void BTab::_ReservedTab7() {}
364 void BTab::_ReservedTab8() {}
365 void BTab::_ReservedTab9() {}
366 void BTab::_ReservedTab10() {}
367 void BTab::_ReservedTab11() {}
368 void BTab::_ReservedTab12() {}
370 BTab
&BTab::operator=(const BTab
&)
372 // this is private and not functional, but exported
377 // #pragma mark - BTabView
380 BTabView::BTabView(const char* name
, button_width width
, uint32 flags
)
384 _InitObject(true, width
);
388 BTabView::BTabView(BRect frame
, const char* name
, button_width width
,
389 uint32 resizeMask
, uint32 flags
)
391 BView(frame
, name
, resizeMask
, flags
)
393 _InitObject(false, width
);
397 BTabView::~BTabView()
399 for (int32 i
= 0; i
< CountTabs(); i
++)
406 BTabView::BTabView(BMessage
* archive
)
408 BView(BUnarchiver::PrepareArchive(archive
)),
410 fContainerView(NULL
),
413 BUnarchiver
unarchiver(archive
);
416 if (archive
->FindInt16("_but_width", &width
) == B_OK
)
417 fTabWidthSetting
= (button_width
)width
;
419 fTabWidthSetting
= B_WIDTH_AS_USUAL
;
421 if (archive
->FindFloat("_high", &fTabHeight
) != B_OK
) {
424 fTabHeight
= ceilf(fh
.ascent
+ fh
.descent
+ fh
.leading
+ 8.0f
);
427 if (archive
->FindInt32("_sel", &fSelection
) != B_OK
)
430 if (archive
->FindInt32("_border_style", (int32
*)&fBorderStyle
) != B_OK
)
431 fBorderStyle
= B_FANCY_BORDER
;
433 if (archive
->FindInt32("_TabSide", (int32
*)&fTabSide
) != B_OK
)
439 if (BUnarchiver::IsArchiveManaged(archive
)) {
441 archive
->GetInfo("_l_items", NULL
, &tabCount
);
442 for (int32 i
= 0; i
< tabCount
; i
++) {
443 unarchiver
.EnsureUnarchived("_l_items", i
);
444 unarchiver
.EnsureUnarchived("_view_list", i
);
449 fContainerView
= ChildAt(0);
450 _InitContainerView(Flags() & B_SUPPORTS_LAYOUT
);
452 while (archive
->FindMessage("_l_items", i
, &tabMsg
) == B_OK
) {
453 BArchivable
* archivedTab
= instantiate_object(&tabMsg
);
456 BTab
* tab
= dynamic_cast<BTab
*>(archivedTab
);
459 if (archive
->FindMessage("_view_list", i
, &viewMsg
) == B_OK
) {
460 BArchivable
* archivedView
= instantiate_object(&viewMsg
);
462 AddTab(dynamic_cast<BView
*>(archivedView
), tab
);
473 BTabView::Instantiate(BMessage
* archive
)
475 if ( validate_instantiation(archive
, "BTabView"))
476 return new BTabView(archive
);
483 BTabView::Archive(BMessage
* archive
, bool deep
) const
485 BArchiver
archiver(archive
);
487 status_t result
= BView::Archive(archive
, deep
);
490 result
= archive
->AddInt16("_but_width", fTabWidthSetting
);
492 result
= archive
->AddFloat("_high", fTabHeight
);
494 result
= archive
->AddInt32("_sel", fSelection
);
495 if (result
== B_OK
&& fBorderStyle
!= B_FANCY_BORDER
)
496 result
= archive
->AddInt32("_border_style", fBorderStyle
);
497 if (result
== B_OK
&& fTabSide
!= kTopSide
)
498 result
= archive
->AddInt32("_TabSide", fTabSide
);
500 if (result
== B_OK
&& deep
) {
501 for (int32 i
= 0; i
< CountTabs(); i
++) {
502 BTab
* tab
= TabAt(i
);
504 if ((result
= archiver
.AddArchivable("_l_items", tab
, deep
))
508 result
= archiver
.AddArchivable("_view_list", tab
->View(), deep
);
512 return archiver
.Finish(result
);
517 BTabView::AllUnarchived(const BMessage
* archive
)
519 status_t err
= BView::AllUnarchived(archive
);
523 fContainerView
= ChildAt(0);
524 _InitContainerView(Flags() & B_SUPPORTS_LAYOUT
);
526 BUnarchiver
unarchiver(archive
);
529 archive
->GetInfo("_l_items", NULL
, &tabCount
);
530 for (int32 i
= 0; i
< tabCount
&& err
== B_OK
; i
++) {
532 err
= unarchiver
.FindObject("_l_items", i
, tab
);
533 if (err
== B_OK
&& tab
) {
535 if ((err
= unarchiver
.FindObject("_view_list", i
,
536 BUnarchiver::B_DONT_ASSUME_OWNERSHIP
, view
)) != B_OK
)
540 fTabList
->AddItem(tab
);
552 BTabView::Perform(perform_code code
, void* _data
)
555 case PERFORM_CODE_ALL_UNARCHIVED
:
557 perform_data_all_unarchived
* data
558 = (perform_data_all_unarchived
*)_data
;
560 data
->return_value
= BTabView::AllUnarchived(data
->archive
);
565 return BView::Perform(code
, _data
);
570 BTabView::AttachedToWindow()
572 BView::AttachedToWindow();
574 if (fSelection
< 0 && CountTabs() > 0)
580 BTabView::DetachedFromWindow()
582 BView::DetachedFromWindow();
587 BTabView::AllAttached()
589 BView::AllAttached();
594 BTabView::AllDetached()
596 BView::AllDetached();
604 BTabView::MessageReceived(BMessage
* message
)
606 switch (message
->what
) {
610 BMessage
reply(B_REPLY
);
611 bool handled
= false;
616 const char* property
;
617 if (message
->GetCurrentSpecifier(&index
, &specifier
, &form
,
618 &property
) == B_OK
) {
619 if (strcmp(property
, "Selection") == 0) {
620 if (message
->what
== B_GET_PROPERTY
) {
621 reply
.AddInt32("result", fSelection
);
626 if (message
->FindInt32("data", &selection
) == B_OK
) {
628 reply
.AddInt32("error", B_OK
);
636 message
->SendReply(&reply
);
638 BView::MessageReceived(message
);
643 case B_MOUSE_WHEEL_CHANGED
:
647 message
->FindFloat("be:wheel_delta_x", &deltaX
);
648 message
->FindFloat("be:wheel_delta_y", &deltaY
);
650 if (deltaX
== 0.0f
&& deltaY
== 0.0f
)
656 int32 selection
= Selection();
657 int32 numTabs
= CountTabs();
658 if (deltaY
> 0 && selection
< numTabs
- 1) {
659 // move to the right tab.
660 Select(Selection() + 1);
661 } else if (deltaY
< 0 && selection
> 0 && numTabs
> 1) {
662 // move to the left tab.
663 Select(selection
- 1);
670 BView::MessageReceived(message
);
677 BTabView::KeyDown(const char* bytes
, int32 numBytes
)
685 int32 focus
= fFocus
- 1;
687 focus
= CountTabs() - 1;
688 SetFocusTab(focus
, true);
693 case B_RIGHT_ARROW
: {
694 int32 focus
= fFocus
+ 1;
695 if (focus
>= CountTabs())
697 SetFocusTab(focus
, true);
707 BView::KeyDown(bytes
, numBytes
);
713 BTabView::MouseDown(BPoint where
)
715 for (int32 i
= 0; i
< CountTabs(); i
++) {
716 if (TabFrame(i
).Contains(where
)
717 && i
!= Selection()) {
723 BView::MouseDown(where
);
728 BTabView::MouseUp(BPoint where
)
730 BView::MouseUp(where
);
735 BTabView::MouseMoved(BPoint where
, uint32 transit
, const BMessage
* dragMessage
)
737 BView::MouseMoved(where
, transit
, dragMessage
);
749 BTabView::Select(int32 index
)
751 if (index
== Selection())
754 if (index
< 0 || index
>= CountTabs())
757 BTab
* tab
= TabAt(Selection());
763 if (tab
!= NULL
&& fContainerView
!= NULL
) {
767 tab
->Select(fContainerView
);
770 // make the view visible through the layout if there is one
772 = dynamic_cast<BCardLayout
*>(fContainerView
->GetLayout());
774 layout
->SetVisibleItem(index
);
779 if (index
!= 0 && !Bounds().Contains(TabFrame(index
))){
780 if (!Bounds().Contains(TabFrame(index
).LeftTop()))
781 fTabOffset
+= TabFrame(index
).left
- Bounds().left
- 20.0f
;
783 fTabOffset
+= TabFrame(index
).right
- Bounds().right
+ 20.0f
;
788 SetFocusTab(index
, true);
793 BTabView::Selection() const
800 BTabView::WindowActivated(bool active
)
802 BView::WindowActivated(active
);
810 BTabView::MakeFocus(bool focus
)
812 BView::MakeFocus(focus
);
814 SetFocusTab(Selection(), focus
);
819 BTabView::SetFocusTab(int32 tab
, bool focus
)
821 if (tab
>= CountTabs())
825 tab
= CountTabs() - 1;
832 if (TabAt (fFocus
) != NULL
)
833 TabAt(fFocus
)->MakeFocus(false);
834 Invalidate(TabFrame(fFocus
));
836 if (TabAt(tab
) != NULL
){
837 TabAt(tab
)->MakeFocus(true);
838 Invalidate(TabFrame(tab
));
841 } else if (fFocus
!= -1) {
842 TabAt(fFocus
)->MakeFocus(false);
843 Invalidate(TabFrame(fFocus
));
850 BTabView::FocusTab() const
857 BTabView::Draw(BRect updateRect
)
860 DrawBox(TabFrame(fSelection
));
862 if (IsFocus() && fFocus
!= -1)
863 TabAt(fFocus
)->DrawFocusMark(this, TabFrame(fFocus
));
870 BRect
bounds(Bounds());
873 rgb_color base
= ui_color(B_PANEL_BACKGROUND_COLOR
);
874 if (fTabSide
== kTopSide
|| fTabSide
== kBottomSide
) {
875 if (fTabSide
== kTopSide
)
876 bounds
.bottom
= fTabHeight
;
878 bounds
.top
= bounds
.bottom
- fTabHeight
;
880 // make a copy for later
882 // draw an inactive tab frame behind all tabs
883 borders
= BControlLook::B_TOP_BORDER
| BControlLook::B_BOTTOM_BORDER
;
884 if (fBorderStyle
== B_NO_BORDER
) {
885 // removes left border that is an artifact of DrawInactiveTab()
888 borders
|= BControlLook::B_LEFT_BORDER
889 | BControlLook::B_RIGHT_BORDER
;
892 // DrawInactiveTab draws 2px border
893 // draw a little wider tab frame to align B_PLAIN_BORDER with it
894 if (fBorderStyle
== B_PLAIN_BORDER
) {
898 } else if (fTabSide
== kLeftSide
|| fTabSide
== kRightSide
) {
899 if (fTabSide
== kLeftSide
)
900 bounds
.right
= fTabHeight
;
902 bounds
.left
= bounds
.right
- fTabHeight
;
904 // make a copy for later
906 // draw an inactive tab frame behind all tabs
907 borders
= BControlLook::B_LEFT_BORDER
| BControlLook::B_RIGHT_BORDER
;
908 if (fBorderStyle
== B_NO_BORDER
) {
909 // removes top border that is an artifact of DrawInactiveTab()
912 borders
|= BControlLook::B_TOP_BORDER
913 | BControlLook::B_BOTTOM_BORDER
;
916 // DrawInactiveTab draws 2px border
917 // draw a little wider tab frame to align B_PLAIN_BORDER with it
918 if (fBorderStyle
== B_PLAIN_BORDER
) {
924 be_control_look
->DrawInactiveTab(this, bounds
, bounds
, base
, 0,
927 // draw the tabs on top of the inactive tab bounds
928 BRect activeTabFrame
;
929 int32 tabCount
= CountTabs();
930 for (int32 i
= 0; i
< tabCount
; i
++) {
931 BRect tabFrame
= TabFrame(i
);
933 activeTabFrame
= tabFrame
;
935 TabAt(i
)->DrawTab(this, tabFrame
,
936 i
== fSelection
? B_TAB_FRONT
:
937 (i
== 0) ? B_TAB_FIRST
: B_TAB_ANY
,
938 i
+ 1 != fSelection
);
942 float lastTab
= 0.0f
;
943 if (fTabSide
== kTopSide
|| fTabSide
== kBottomSide
) {
944 lastTab
= TabFrame(tabCount
- 1).right
;
946 tabsBounds
.left
= tabsBounds
.right
= lastTab
;
947 borders
= BControlLook::B_TOP_BORDER
| BControlLook::B_BOTTOM_BORDER
;
948 } else if (fTabSide
== kLeftSide
|| fTabSide
== kRightSide
) {
949 lastTab
= TabFrame(tabCount
- 1).bottom
;
950 last
= bounds
.bottom
;
951 tabsBounds
.top
= tabsBounds
.bottom
= lastTab
;
952 borders
= BControlLook::B_LEFT_BORDER
| BControlLook::B_RIGHT_BORDER
;
955 if (lastTab
< last
) {
956 // draw a 1px right border on the last tab
957 be_control_look
->DrawInactiveTab(this, tabsBounds
, tabsBounds
, base
, 0,
961 return fSelection
< CountTabs() ? TabFrame(fSelection
) : BRect();
966 BTabView::DrawBox(BRect selectedTabRect
)
968 BRect
rect(Bounds());
969 uint32 bordersToDraw
= BControlLook::B_ALL_BORDERS
;
972 bordersToDraw
&= ~BControlLook::B_TOP_BORDER
;
973 rect
.top
= fTabHeight
;
976 bordersToDraw
&= ~BControlLook::B_BOTTOM_BORDER
;
977 rect
.bottom
-= fTabHeight
;
980 bordersToDraw
&= ~BControlLook::B_LEFT_BORDER
;
981 rect
.left
= fTabHeight
;
984 bordersToDraw
&= ~BControlLook::B_RIGHT_BORDER
;
985 rect
.right
-= fTabHeight
;
989 rgb_color base
= ui_color(B_PANEL_BACKGROUND_COLOR
);
990 if (fBorderStyle
== B_FANCY_BORDER
)
991 be_control_look
->DrawGroupFrame(this, rect
, rect
, base
, bordersToDraw
);
992 else if (fBorderStyle
== B_PLAIN_BORDER
) {
993 be_control_look
->DrawBorder(this, rect
, rect
, base
, B_PLAIN_BORDER
,
996 ; // B_NO_BORDER draws no box
1001 BTabView::TabFrame(int32 index
) const
1003 if (index
>= CountTabs() || index
< 0)
1006 float width
= 100.0f
;
1007 float height
= fTabHeight
;
1008 float offset
= BControlLook::ComposeSpacing(B_USE_WINDOW_SPACING
);
1009 BRect
bounds(Bounds());
1011 switch (fTabWidthSetting
) {
1012 case B_WIDTH_FROM_LABEL
:
1015 for (int32 i
= 0; i
< index
; i
++){
1016 x
+= StringWidth(TabAt(i
)->Label()) + 20.0f
;
1021 return BRect(offset
+ x
, 0.0f
,
1022 offset
+ x
+ StringWidth(TabAt(index
)->Label()) + 20.0f
,
1025 return BRect(offset
+ x
, bounds
.bottom
- height
,
1026 offset
+ x
+ StringWidth(TabAt(index
)->Label()) + 20.0f
,
1029 return BRect(0.0f
, offset
+ x
, height
, offset
+ x
1030 + StringWidth(TabAt(index
)->Label()) + 20.0f
);
1032 return BRect(bounds
.right
- height
, offset
+ x
,
1033 bounds
.right
, offset
+ x
1034 + StringWidth(TabAt(index
)->Label()) + 20.0f
);
1040 case B_WIDTH_FROM_WIDEST
:
1042 for (int32 i
= 0; i
< CountTabs(); i
++) {
1043 float tabWidth
= StringWidth(TabAt(i
)->Label()) + 20.0f
;
1044 if (tabWidth
> width
)
1049 case B_WIDTH_AS_USUAL
:
1053 return BRect(offset
+ index
* width
, 0.0f
,
1054 offset
+ index
* width
+ width
, height
);
1056 return BRect(offset
+ index
* width
, bounds
.bottom
- height
,
1057 offset
+ index
* width
+ width
, bounds
.bottom
);
1059 return BRect(0.0f
, offset
+ index
* width
, height
,
1060 offset
+ index
* width
+ width
);
1062 return BRect(bounds
.right
- height
, offset
+ index
* width
,
1063 bounds
.right
, offset
+ index
* width
+ width
);
1072 BTabView::SetFlags(uint32 flags
)
1074 BView::SetFlags(flags
);
1079 BTabView::SetResizingMode(uint32 mode
)
1081 BView::SetResizingMode(mode
);
1089 BTabView::ResizeToPreferred()
1091 BView::ResizeToPreferred();
1096 BTabView::GetPreferredSize(float* _width
, float* _height
)
1098 BView::GetPreferredSize(_width
, _height
);
1107 size
= GetLayout()->MinSize();
1109 size
= _TabsMinSize();
1110 BSize containerSize
= fContainerView
->MinSize();
1111 containerSize
.width
+= 2 * _BorderWidth();
1112 containerSize
.height
+= 2 * _BorderWidth();
1113 if (containerSize
.width
> size
.width
)
1114 size
.width
= containerSize
.width
;
1115 size
.height
+= containerSize
.height
;
1117 return BLayoutUtils::ComposeSize(ExplicitMinSize(), size
);
1126 size
= GetLayout()->MaxSize();
1128 size
= _TabsMinSize();
1129 BSize containerSize
= fContainerView
->MaxSize();
1130 containerSize
.width
+= 2 * _BorderWidth();
1131 containerSize
.height
+= 2 * _BorderWidth();
1132 if (containerSize
.width
> size
.width
)
1133 size
.width
= containerSize
.width
;
1134 size
.height
+= containerSize
.height
;
1136 return BLayoutUtils::ComposeSize(ExplicitMaxSize(), size
);
1141 BTabView::PreferredSize()
1144 if (GetLayout() != NULL
)
1145 size
= GetLayout()->PreferredSize();
1147 size
= _TabsMinSize();
1148 BSize containerSize
= fContainerView
->PreferredSize();
1149 containerSize
.width
+= 2 * _BorderWidth();
1150 containerSize
.height
+= 2 * _BorderWidth();
1151 if (containerSize
.width
> size
.width
)
1152 size
.width
= containerSize
.width
;
1153 size
.height
+= containerSize
.height
;
1155 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), size
);
1160 BTabView::FrameMoved(BPoint newPosition
)
1162 BView::FrameMoved(newPosition
);
1167 BTabView::FrameResized(float newWidth
, float newHeight
)
1169 BView::FrameResized(newWidth
, newHeight
);
1177 BTabView::ResolveSpecifier(BMessage
* message
, int32 index
,
1178 BMessage
* specifier
, int32 what
, const char* property
)
1180 BPropertyInfo
propInfo(sPropertyList
);
1182 if (propInfo
.FindMatch(message
, 0, specifier
, what
, property
) >= B_OK
)
1185 return BView::ResolveSpecifier(message
, index
, specifier
, what
, property
);
1190 BTabView::GetSupportedSuites(BMessage
* message
)
1192 message
->AddString("suites", "suite/vnd.Be-tab-view");
1194 BPropertyInfo
propInfo(sPropertyList
);
1195 message
->AddFlat("messages", &propInfo
);
1197 return BView::GetSupportedSuites(message
);
1205 BTabView::AddTab(BView
* target
, BTab
* tab
)
1208 tab
= new BTab(target
);
1210 tab
->SetView(target
);
1212 if (fContainerView
->GetLayout())
1213 fContainerView
->GetLayout()->AddView(CountTabs(), target
);
1215 fTabList
->AddItem(tab
);
1216 BTab::Private(tab
).SetTabView(this);
1218 // When we haven't had a any tabs before, but are already attached to the
1219 // window, select this one.
1220 if (CountTabs() == 1 && Window() != NULL
)
1226 BTabView::RemoveTab(int32 index
)
1228 if (index
< 0 || index
>= CountTabs())
1231 BTab
* tab
= (BTab
*)fTabList
->RemoveItem(index
);
1236 BTab::Private(tab
).SetTabView(NULL
);
1238 if (fContainerView
->GetLayout())
1239 fContainerView
->GetLayout()->RemoveItem(index
);
1241 if (CountTabs() == 0)
1243 else if (index
<= fSelection
)
1244 Select(fSelection
- 1);
1247 if (fFocus
== CountTabs() - 1 || CountTabs() == 0)
1248 SetFocusTab(fFocus
, false);
1250 SetFocusTab(fFocus
, true);
1258 BTabView::TabAt(int32 index
) const
1260 return (BTab
*)fTabList
->ItemAt(index
);
1265 BTabView::SetTabWidth(button_width width
)
1267 fTabWidthSetting
= width
;
1274 BTabView::TabWidth() const
1276 return fTabWidthSetting
;
1281 BTabView::SetTabHeight(float height
)
1283 if (fTabHeight
== height
)
1286 fTabHeight
= height
;
1287 _LayoutContainerView(GetLayout() != NULL
);
1294 BTabView::TabHeight() const
1301 BTabView::SetBorder(border_style borderStyle
)
1303 if (fBorderStyle
== borderStyle
)
1306 fBorderStyle
= borderStyle
;
1308 _LayoutContainerView((Flags() & B_SUPPORTS_LAYOUT
) != 0);
1313 BTabView::Border() const
1315 return fBorderStyle
;
1320 BTabView::SetTabSide(tab_side tabSide
)
1322 if (fTabSide
== tabSide
)
1326 _LayoutContainerView(Flags() & B_SUPPORTS_LAYOUT
);
1331 BTabView::TabSide() const
1338 BTabView::ContainerView() const
1340 return fContainerView
;
1345 BTabView::CountTabs() const
1347 return fTabList
->CountItems();
1352 BTabView::ViewForTab(int32 tabIndex
) const
1354 BTab
* tab
= TabAt(tabIndex
);
1363 BTabView::_InitObject(bool layouted
, button_width width
)
1365 fTabList
= new BList
;
1367 fTabWidthSetting
= width
;
1371 fBorderStyle
= B_FANCY_BORDER
;
1372 fTabSide
= kTopSide
;
1374 SetViewUIColor(B_PANEL_BACKGROUND_COLOR
);
1375 SetLowUIColor(B_PANEL_BACKGROUND_COLOR
);
1379 fTabHeight
= ceilf(fh
.ascent
+ fh
.descent
+ fh
.leading
+ 8.0f
);
1381 fContainerView
= NULL
;
1382 _InitContainerView(layouted
);
1387 BTabView::_InitContainerView(bool layouted
)
1389 bool needsLayout
= false;
1390 bool createdContainer
= false;
1392 if (GetLayout() == NULL
) {
1393 SetLayout(new(std::nothrow
) BGroupLayout(B_HORIZONTAL
));
1397 if (fContainerView
== NULL
) {
1398 fContainerView
= new BView("view container", B_WILL_DRAW
);
1399 fContainerView
->SetLayout(new(std::nothrow
) BCardLayout());
1400 createdContainer
= true;
1402 } else if (fContainerView
== NULL
) {
1403 fContainerView
= new BView(Bounds(), "view container", B_FOLLOW_ALL
,
1405 createdContainer
= true;
1408 if (needsLayout
|| createdContainer
)
1409 _LayoutContainerView(layouted
);
1411 if (createdContainer
) {
1412 fContainerView
->SetViewUIColor(B_PANEL_BACKGROUND_COLOR
);
1413 fContainerView
->SetLowUIColor(B_PANEL_BACKGROUND_COLOR
);
1414 AddChild(fContainerView
);
1420 BTabView::_TabsMinSize() const
1422 BSize
size(0.0f
, TabHeight());
1423 int32 count
= min_c(2, CountTabs());
1424 for (int32 i
= 0; i
< count
; i
++) {
1425 BRect frame
= TabFrame(i
);
1426 size
.width
+= frame
.Width();
1429 if (count
< CountTabs()) {
1430 // TODO: Add size for yet to be implemented buttons that allow
1431 // "scrolling" the displayed tabs left/right.
1439 BTabView::_BorderWidth() const
1441 switch (fBorderStyle
) {
1443 case B_FANCY_BORDER
:
1446 case B_PLAIN_BORDER
:
1456 BTabView::_LayoutContainerView(bool layouted
)
1458 float borderWidth
= _BorderWidth();
1460 float topBorderOffset
;
1461 switch (fBorderStyle
) {
1463 case B_FANCY_BORDER
:
1464 topBorderOffset
= 1.0f
;
1467 case B_PLAIN_BORDER
:
1468 topBorderOffset
= 0.0f
;
1472 topBorderOffset
= -1.0f
;
1475 BGroupLayout
* layout
= dynamic_cast<BGroupLayout
*>(GetLayout());
1476 if (layout
!= NULL
) {
1477 float inset
= borderWidth
+ TabHeight() - topBorderOffset
;
1480 layout
->SetInsets(borderWidth
, inset
, borderWidth
,
1484 layout
->SetInsets(borderWidth
, borderWidth
, borderWidth
,
1488 layout
->SetInsets(inset
, borderWidth
, borderWidth
,
1492 layout
->SetInsets(borderWidth
, borderWidth
, inset
,
1498 BRect bounds
= Bounds();
1501 bounds
.top
+= TabHeight();
1504 bounds
.bottom
-= TabHeight();
1507 bounds
.left
+= TabHeight();
1510 bounds
.right
-= TabHeight();
1513 bounds
.InsetBy(borderWidth
, borderWidth
);
1515 fContainerView
->MoveTo(bounds
.left
, bounds
.top
);
1516 fContainerView
->ResizeTo(bounds
.Width(), bounds
.Height());
1521 // #pragma mark - FBC and forbidden
1524 void BTabView::_ReservedTabView3() {}
1525 void BTabView::_ReservedTabView4() {}
1526 void BTabView::_ReservedTabView5() {}
1527 void BTabView::_ReservedTabView6() {}
1528 void BTabView::_ReservedTabView7() {}
1529 void BTabView::_ReservedTabView8() {}
1530 void BTabView::_ReservedTabView9() {}
1531 void BTabView::_ReservedTabView10() {}
1532 void BTabView::_ReservedTabView11() {}
1533 void BTabView::_ReservedTabView12() {}
1536 BTabView::BTabView(const BTabView
& tabView
)
1539 // this is private and not functional, but exported
1544 BTabView::operator=(const BTabView
&)
1546 // this is private and not functional, but exported
1550 // #pragma mark - binary compatibility
1554 B_IF_GCC_2(_ReservedTabView1__8BTabView
, _ZN8BTabView17_ReservedTabView1Ev
)(
1555 BTabView
* tabView
, border_style borderStyle
)
1557 tabView
->BTabView::SetBorder(borderStyle
);
1561 B_IF_GCC_2(_ReservedTabView2__8BTabView
, _ZN8BTabView17_ReservedTabView2Ev
)(
1562 BTabView
* tabView
, BTabView::tab_side tabSide
)
1564 tabView
->BTabView::SetTabSide(tabSide
);