tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / kits / interface / TabView.cpp
blob28c93c6c33dc159b80193e561e8668685d85f7fb
1 /*
2 * Copyright 2001-2013 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Marc Flerackers (mflerackers@androme.be)
7 * Jérôme Duval (korli@users.berlios.de)
8 * Stephan Aßmus <superstippi@gmx.de>
9 * Artur Wyszynski
10 * Rene Gollent (rene@gollent.com)
14 #include <TabView.h>
15 #include <TabViewPrivate.h>
17 #include <new>
18 #include <string.h>
20 #include <CardLayout.h>
21 #include <ControlLook.h>
22 #include <GroupLayout.h>
23 #include <LayoutUtils.h>
24 #include <List.h>
25 #include <Message.h>
26 #include <PropertyInfo.h>
27 #include <Rect.h>
28 #include <Region.h>
29 #include <String.h>
31 #include <binary_compatibility/Support.h>
34 using std::nothrow;
37 static property_info sPropertyList[] = {
39 "Selection",
40 { B_GET_PROPERTY, B_SET_PROPERTY },
41 { B_DIRECT_SPECIFIER },
42 NULL, 0,
43 { B_INT32_TYPE }
51 BTab::BTab(BView* contentsView)
53 fEnabled(true),
54 fSelected(false),
55 fFocus(false),
56 fView(contentsView),
57 fTabView(NULL)
62 BTab::BTab(BMessage* archive)
64 BArchivable(archive),
65 fSelected(false),
66 fFocus(false),
67 fView(NULL),
68 fTabView(NULL)
70 bool disable;
72 if (archive->FindBool("_disable", &disable) != B_OK)
73 SetEnabled(true);
74 else
75 SetEnabled(!disable);
79 BTab::~BTab()
81 if (fView == NULL)
82 return;
84 if (fSelected)
85 fView->RemoveSelf();
87 delete fView;
91 BArchivable*
92 BTab::Instantiate(BMessage* archive)
94 if (validate_instantiation(archive, "BTab"))
95 return new BTab(archive);
97 return NULL;
101 status_t
102 BTab::Archive(BMessage* data, bool deep) const
104 status_t result = BArchivable::Archive(data, deep);
105 if (result != B_OK)
106 return result;
108 if (!fEnabled)
109 result = data->AddBool("_disable", false);
111 return result;
115 status_t
116 BTab::Perform(uint32 d, void* arg)
118 return BArchivable::Perform(d, arg);
122 const char*
123 BTab::Label() const
125 if (fView != NULL)
126 return fView->Name();
127 else
128 return NULL;
132 void
133 BTab::SetLabel(const char* label)
135 if (label == NULL || fView == NULL)
136 return;
138 fView->SetName(label);
140 if (fTabView != NULL)
141 fTabView->Invalidate();
145 bool
146 BTab::IsSelected() const
148 return fSelected;
152 void
153 BTab::Select(BView* owner)
155 fSelected = true;
157 if (owner == NULL || fView == NULL)
158 return;
160 // NOTE: Views are not added/removed, if there is layout,
161 // they are made visible/invisible in that case.
162 if (owner->GetLayout() == NULL && fView->Parent() == NULL)
163 owner->AddChild(fView);
167 void
168 BTab::Deselect()
170 if (fView != NULL) {
171 // NOTE: Views are not added/removed, if there is layout,
172 // they are made visible/invisible in that case.
173 bool removeView = false;
174 BView* container = fView->Parent();
175 if (container != NULL)
176 removeView =
177 dynamic_cast<BCardLayout*>(container->GetLayout()) == NULL;
178 if (removeView)
179 fView->RemoveSelf();
182 fSelected = false;
186 void
187 BTab::SetEnabled(bool enable)
189 fEnabled = enable;
193 bool
194 BTab::IsEnabled() const
196 return fEnabled;
200 void
201 BTab::MakeFocus(bool focus)
203 fFocus = focus;
207 bool
208 BTab::IsFocus() const
210 return fFocus;
214 void
215 BTab::SetView(BView* view)
217 if (view == NULL || fView == view)
218 return;
220 if (fView != NULL) {
221 fView->RemoveSelf();
222 delete fView;
224 fView = view;
226 if (fTabView != NULL && fSelected) {
227 Select(fTabView->ContainerView());
228 fTabView->Invalidate();
233 BView*
234 BTab::View() const
236 return fView;
240 void
241 BTab::DrawFocusMark(BView* owner, BRect frame)
243 float width = owner->StringWidth(Label());
245 owner->SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
247 float offset = IsSelected() ? 3 : 2;
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));
255 void
256 BTab::DrawLabel(BView* owner, BRect frame)
258 be_control_look->DrawLabel(owner, Label(), frame, frame,
259 ui_color(B_PANEL_BACKGROUND_COLOR),
260 IsEnabled() ? 0 : BPrivate::BControlLook::B_DISABLED,
261 BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER));
265 void
266 BTab::DrawTab(BView* owner, BRect frame, tab_position position, bool full)
268 rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR);
269 uint32 borders = BControlLook::B_TOP_BORDER
270 | BControlLook::B_BOTTOM_BORDER;
272 if (frame.left == owner->Bounds().left)
273 borders |= BControlLook::B_LEFT_BORDER;
275 if (frame.right == owner->Bounds().right)
276 borders |= BControlLook::B_RIGHT_BORDER;
278 if (position == B_TAB_FRONT) {
279 frame.bottom += 1;
280 be_control_look->DrawActiveTab(owner, frame, frame, no_tint, 0,
281 borders);
282 } else {
283 be_control_look->DrawInactiveTab(owner, frame, frame, no_tint, 0,
284 borders);
287 DrawLabel(owner, frame);
291 // #pragma mark - FBC padding and private methods
294 void BTab::_ReservedTab1() {}
295 void BTab::_ReservedTab2() {}
296 void BTab::_ReservedTab3() {}
297 void BTab::_ReservedTab4() {}
298 void BTab::_ReservedTab5() {}
299 void BTab::_ReservedTab6() {}
300 void BTab::_ReservedTab7() {}
301 void BTab::_ReservedTab8() {}
302 void BTab::_ReservedTab9() {}
303 void BTab::_ReservedTab10() {}
304 void BTab::_ReservedTab11() {}
305 void BTab::_ReservedTab12() {}
307 BTab &BTab::operator=(const BTab &)
309 // this is private and not functional, but exported
310 return *this;
314 // #pragma mark - BTabView
317 BTabView::BTabView(const char* name, button_width width, uint32 flags)
319 BView(name, flags)
321 _InitObject(true, width);
325 BTabView::BTabView(BRect frame, const char* name, button_width width,
326 uint32 resizeMask, uint32 flags)
328 BView(frame, name, resizeMask, flags)
330 _InitObject(false, width);
334 BTabView::~BTabView()
336 for (int32 i = 0; i < CountTabs(); i++)
337 delete TabAt(i);
339 delete fTabList;
343 BTabView::BTabView(BMessage* archive)
345 BView(BUnarchiver::PrepareArchive(archive)),
346 fTabList(new BList),
347 fContainerView(NULL),
348 fFocus(-1)
350 BUnarchiver unarchiver(archive);
352 int16 width;
353 if (archive->FindInt16("_but_width", &width) == B_OK)
354 fTabWidthSetting = (button_width)width;
355 else
356 fTabWidthSetting = B_WIDTH_AS_USUAL;
358 if (archive->FindFloat("_high", &fTabHeight) != B_OK) {
359 font_height fh;
360 GetFontHeight(&fh);
361 fTabHeight = fh.ascent + fh.descent + fh.leading + 8.0f;
364 if (archive->FindInt32("_sel", &fSelection) != B_OK)
365 fSelection = -1;
367 if (archive->FindInt32("_border_style", (int32*)&fBorderStyle) != B_OK)
368 fBorderStyle = B_FANCY_BORDER;
370 int32 i = 0;
371 BMessage tabMsg;
373 if (BUnarchiver::IsArchiveManaged(archive)) {
374 int32 tabCount;
375 archive->GetInfo("_l_items", NULL, &tabCount);
376 for (int32 i = 0; i < tabCount; i++) {
377 unarchiver.EnsureUnarchived("_l_items", i);
378 unarchiver.EnsureUnarchived("_view_list", i);
380 return;
383 fContainerView = ChildAt(0);
384 _InitContainerView(Flags() & B_SUPPORTS_LAYOUT);
386 while (archive->FindMessage("_l_items", i, &tabMsg) == B_OK) {
387 BArchivable* archivedTab = instantiate_object(&tabMsg);
389 if (archivedTab) {
390 BTab* tab = dynamic_cast<BTab*>(archivedTab);
392 BMessage viewMsg;
393 if (archive->FindMessage("_view_list", i, &viewMsg) == B_OK) {
394 BArchivable* archivedView = instantiate_object(&viewMsg);
395 if (archivedView)
396 AddTab(dynamic_cast<BView*>(archivedView), tab);
400 tabMsg.MakeEmpty();
401 i++;
406 BArchivable*
407 BTabView::Instantiate(BMessage* archive)
409 if ( validate_instantiation(archive, "BTabView"))
410 return new BTabView(archive);
412 return NULL;
416 status_t
417 BTabView::Archive(BMessage* archive, bool deep) const
419 BArchiver archiver(archive);
421 status_t result = BView::Archive(archive, deep);
423 if (result == B_OK)
424 result = archive->AddInt16("_but_width", fTabWidthSetting);
425 if (result == B_OK)
426 result = archive->AddFloat("_high", fTabHeight);
427 if (result == B_OK)
428 result = archive->AddInt32("_sel", fSelection);
429 if (result == B_OK && fBorderStyle != B_FANCY_BORDER)
430 result = archive->AddInt32("_border_style", fBorderStyle);
432 if (result == B_OK && deep) {
433 for (int32 i = 0; i < CountTabs(); i++) {
434 BTab* tab = TabAt(i);
436 if ((result = archiver.AddArchivable("_l_items", tab, deep)) != B_OK)
437 break;
438 result = archiver.AddArchivable("_view_list", tab->View(), deep);
442 return archiver.Finish(result);
446 status_t
447 BTabView::AllUnarchived(const BMessage* archive)
449 status_t err = BView::AllUnarchived(archive);
450 if (err != B_OK)
451 return err;
453 fContainerView = ChildAt(0);
454 _InitContainerView(Flags() & B_SUPPORTS_LAYOUT);
456 BUnarchiver unarchiver(archive);
458 int32 tabCount;
459 archive->GetInfo("_l_items", NULL, &tabCount);
460 for (int32 i = 0; i < tabCount && err == B_OK; i++) {
461 BTab* tab;
462 err = unarchiver.FindObject("_l_items", i, tab);
463 if (err == B_OK && tab) {
464 BView* view;
465 if ((err = unarchiver.FindObject("_view_list", i,
466 BUnarchiver::B_DONT_ASSUME_OWNERSHIP, view)) != B_OK)
467 break;
469 tab->SetView(view);
470 fTabList->AddItem(tab);
474 if (err == B_OK)
475 Select(fSelection);
477 return err;
481 status_t
482 BTabView::Perform(perform_code code, void* _data)
484 switch (code) {
485 case PERFORM_CODE_ALL_UNARCHIVED:
487 perform_data_all_unarchived* data
488 = (perform_data_all_unarchived*)_data;
490 data->return_value = BTabView::AllUnarchived(data->archive);
491 return B_OK;
495 return BView::Perform(code, _data);
499 void
500 BTabView::AttachedToWindow()
502 BView::AttachedToWindow();
504 if (fSelection < 0 && CountTabs() > 0)
505 Select(0);
509 void
510 BTabView::DetachedFromWindow()
512 BView::DetachedFromWindow();
516 void
517 BTabView::AllAttached()
519 BView::AllAttached();
523 void
524 BTabView::AllDetached()
526 BView::AllDetached();
530 // #pragma mark -
533 void
534 BTabView::MessageReceived(BMessage* message)
536 switch (message->what) {
537 case B_GET_PROPERTY:
538 case B_SET_PROPERTY:
540 BMessage reply(B_REPLY);
541 bool handled = false;
543 BMessage specifier;
544 int32 index;
545 int32 form;
546 const char* property;
547 if (message->GetCurrentSpecifier(&index, &specifier, &form, &property) == B_OK) {
548 if (strcmp(property, "Selection") == 0) {
549 if (message->what == B_GET_PROPERTY) {
550 reply.AddInt32("result", fSelection);
551 handled = true;
552 } else {
553 // B_GET_PROPERTY
554 int32 selection;
555 if (message->FindInt32("data", &selection) == B_OK) {
556 Select(selection);
557 reply.AddInt32("error", B_OK);
558 handled = true;
564 if (handled)
565 message->SendReply(&reply);
566 else
567 BView::MessageReceived(message);
568 break;
571 #if 0
572 case B_MOUSE_WHEEL_CHANGED:
574 float deltaX = 0.0f;
575 float deltaY = 0.0f;
576 message->FindFloat("be:wheel_delta_x", &deltaX);
577 message->FindFloat("be:wheel_delta_y", &deltaY);
579 if (deltaX == 0.0f && deltaY == 0.0f)
580 return;
582 if (deltaY == 0.0f)
583 deltaY = deltaX;
585 int32 selection = Selection();
586 int32 numTabs = CountTabs();
587 if (deltaY > 0 && selection < numTabs - 1) {
588 // move to the right tab.
589 Select(Selection() + 1);
590 } else if (deltaY < 0 && selection > 0 && numTabs > 1) {
591 // move to the left tab.
592 Select(selection - 1);
594 break;
596 #endif
598 default:
599 BView::MessageReceived(message);
600 break;
605 void
606 BTabView::KeyDown(const char* bytes, int32 numBytes)
608 if (IsHidden())
609 return;
611 switch (bytes[0]) {
612 case B_DOWN_ARROW:
613 case B_LEFT_ARROW: {
614 int32 focus = fFocus - 1;
615 if (focus < 0)
616 focus = CountTabs() - 1;
617 SetFocusTab(focus, true);
618 break;
621 case B_UP_ARROW:
622 case B_RIGHT_ARROW: {
623 int32 focus = fFocus + 1;
624 if (focus >= CountTabs())
625 focus = 0;
626 SetFocusTab(focus, true);
627 break;
630 case B_RETURN:
631 case B_SPACE:
632 Select(FocusTab());
633 break;
635 default:
636 BView::KeyDown(bytes, numBytes);
641 void
642 BTabView::MouseDown(BPoint where)
644 if (where.y > fTabHeight)
645 return;
647 for (int32 i = 0; i < CountTabs(); i++) {
648 if (TabFrame(i).Contains(where)
649 && i != Selection()) {
650 Select(i);
651 return;
655 BView::MouseDown(where);
659 void
660 BTabView::MouseUp(BPoint where)
662 BView::MouseUp(where);
666 void
667 BTabView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
669 BView::MouseMoved(where, transit, dragMessage);
673 void
674 BTabView::Pulse()
676 BView::Pulse();
680 void
681 BTabView::Select(int32 index)
683 if (index == Selection())
684 return;
686 if (index < 0 || index >= CountTabs())
687 index = Selection();
689 BTab* tab = TabAt(Selection());
691 if (tab)
692 tab->Deselect();
694 tab = TabAt(index);
695 if (tab != NULL && fContainerView != NULL) {
696 if (index == 0)
697 fTabOffset = 0.0f;
698 tab->Select(fContainerView);
699 fSelection = index;
701 // make the view visible through the layout if there is one
702 BCardLayout* layout
703 = dynamic_cast<BCardLayout*>(fContainerView->GetLayout());
704 if (layout != NULL)
705 layout->SetVisibleItem(index);
708 Invalidate();
710 if (index != 0 && !Bounds().Contains(TabFrame(index))){
711 if (!Bounds().Contains(TabFrame(index).LeftTop()))
712 fTabOffset += TabFrame(index).left - Bounds().left - 20.0f;
713 else
714 fTabOffset += TabFrame(index).right - Bounds().right + 20.0f;
716 Invalidate();
719 SetFocusTab(index, true);
723 int32
724 BTabView::Selection() const
726 return fSelection;
730 void
731 BTabView::WindowActivated(bool active)
733 BView::WindowActivated(active);
735 if (IsFocus())
736 Invalidate();
740 void
741 BTabView::MakeFocus(bool focus)
743 BView::MakeFocus(focus);
745 SetFocusTab(Selection(), focus);
749 void
750 BTabView::SetFocusTab(int32 tab, bool focus)
752 if (tab >= CountTabs())
753 tab = 0;
755 if (tab < 0)
756 tab = CountTabs() - 1;
758 if (focus) {
759 if (tab == fFocus)
760 return;
762 if (fFocus != -1){
763 if (TabAt (fFocus) != NULL)
764 TabAt(fFocus)->MakeFocus(false);
765 Invalidate(TabFrame(fFocus));
767 if (TabAt(tab) != NULL){
768 TabAt(tab)->MakeFocus(true);
769 Invalidate(TabFrame(tab));
770 fFocus = tab;
772 } else if (fFocus != -1) {
773 TabAt(fFocus)->MakeFocus(false);
774 Invalidate(TabFrame(fFocus));
775 fFocus = -1;
780 int32
781 BTabView::FocusTab() const
783 return fFocus;
787 void
788 BTabView::Draw(BRect updateRect)
790 DrawBox(TabFrame(fSelection));
791 DrawTabs();
793 if (IsFocus() && fFocus != -1)
794 TabAt(fFocus)->DrawFocusMark(this, TabFrame(fFocus));
798 BRect
799 BTabView::DrawTabs()
801 float left = 0;
803 for (int32 i = 0; i < CountTabs(); i++) {
804 BRect tabFrame = TabFrame(i);
805 TabAt(i)->DrawTab(this, tabFrame,
806 i == fSelection ? B_TAB_FRONT : (i == 0) ? B_TAB_FIRST : B_TAB_ANY,
807 i + 1 != fSelection);
808 left = tabFrame.right;
811 BRect frame(Bounds());
812 if (fBorderStyle == B_PLAIN_BORDER)
813 frame.right += 1;
814 else if (fBorderStyle == B_NO_BORDER)
815 frame.right += 2;
816 if (left < frame.right) {
817 frame.left = left;
818 frame.bottom = fTabHeight;
819 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
820 uint32 borders = BControlLook::B_TOP_BORDER
821 | BControlLook::B_BOTTOM_BORDER | BControlLook::B_RIGHT_BORDER;
822 if (left == 0)
823 borders |= BControlLook::B_LEFT_BORDER;
824 be_control_look->DrawInactiveTab(this, frame, frame, base, 0,
825 borders);
827 if (fBorderStyle == B_NO_BORDER) {
828 // Draw a small inactive area before first tab.
829 frame = Bounds();
830 frame.right = 0.0f;
831 // one pixel wide
832 frame.bottom = fTabHeight;
833 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
834 uint32 borders = BControlLook::B_TOP_BORDER
835 | BControlLook::B_BOTTOM_BORDER;
836 be_control_look->DrawInactiveTab(this, frame, frame, base, 0,
837 borders);
840 if (fSelection < CountTabs())
841 return TabFrame(fSelection);
843 return BRect();
847 void
848 BTabView::DrawBox(BRect selTabRect)
850 BRect rect(Bounds());
851 rect.top = selTabRect.bottom;
852 if (fBorderStyle != B_FANCY_BORDER)
853 rect.top += 1.0f;
854 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
856 if (fBorderStyle == B_FANCY_BORDER)
857 be_control_look->DrawGroupFrame(this, rect, rect, base);
858 else {
859 uint32 borders = BControlLook::B_TOP_BORDER;
860 if (fBorderStyle == B_PLAIN_BORDER)
861 borders = BControlLook::B_ALL_BORDERS;
862 be_control_look->DrawBorder(this, rect, rect, base, B_PLAIN_BORDER,
863 0, borders);
868 BRect
869 BTabView::TabFrame(int32 index) const
871 if (index >= CountTabs() || index < 0)
872 return BRect();
874 float width = 100.0f;
875 float height = fTabHeight;
876 float borderOffset = 0.0f;
877 // Do not use 2.0f for B_NO_BORDER, that will look yet different
878 // again (handled in DrawTabs()).
879 if (fBorderStyle == B_PLAIN_BORDER)
880 borderOffset = 1.0f;
881 switch (fTabWidthSetting) {
882 case B_WIDTH_FROM_LABEL:
884 float x = 0.0f;
885 for (int32 i = 0; i < index; i++){
886 x += StringWidth(TabAt(i)->Label()) + 20.0f;
889 return BRect(x - borderOffset, 0.0f,
890 x + StringWidth(TabAt(index)->Label()) + 20.0f
891 - borderOffset,
892 height);
895 case B_WIDTH_FROM_WIDEST:
896 width = 0.0;
897 for (int32 i = 0; i < CountTabs(); i++) {
898 float tabWidth = StringWidth(TabAt(i)->Label()) + 20.0f;
899 if (tabWidth > width)
900 width = tabWidth;
902 // fall through
904 case B_WIDTH_AS_USUAL:
905 default:
906 return BRect(index * width - borderOffset, 0.0f,
907 index * width + width - borderOffset, height);
910 // TODO: fix to remove "offset" in DrawTab and DrawLabel ...
911 switch (fTabWidthSetting) {
912 case B_WIDTH_FROM_LABEL:
914 float x = 6.0f;
915 for (int32 i = 0; i < index; i++){
916 x += StringWidth(TabAt(i)->Label()) + 20.0f;
919 return BRect(x - fTabOffset, 0.0f,
920 x - fTabOffset + StringWidth(TabAt(index)->Label()) + 20.0f,
921 fTabHeight);
924 case B_WIDTH_FROM_WIDEST:
926 float width = 0.0f;
928 for (int32 i = 0; i < CountTabs(); i++) {
929 float tabWidth = StringWidth(TabAt(i)->Label()) + 20.0f;
930 if (tabWidth > width)
931 width = tabWidth;
933 return BRect((6.0f + index * width) - fTabOffset, 0.0f,
934 (6.0f + index * width + width) - fTabOffset, fTabHeight);
937 case B_WIDTH_AS_USUAL:
938 default:
939 return BRect((6.0f + index * 100.0f) - fTabOffset, 0.0f,
940 (6.0f + index * 100.0f + 100.0f) - fTabOffset, fTabHeight);
945 void
946 BTabView::SetFlags(uint32 flags)
948 BView::SetFlags(flags);
952 void
953 BTabView::SetResizingMode(uint32 mode)
955 BView::SetResizingMode(mode);
959 // #pragma mark -
962 void
963 BTabView::ResizeToPreferred()
965 BView::ResizeToPreferred();
969 void
970 BTabView::GetPreferredSize(float* _width, float* _height)
972 BView::GetPreferredSize(_width, _height);
976 BSize
977 BTabView::MinSize()
979 BSize size;
980 if (GetLayout())
981 size = GetLayout()->MinSize();
982 else {
983 size = _TabsMinSize();
984 BSize containerSize = fContainerView->MinSize();
985 containerSize.width += 2 * _BorderWidth();
986 containerSize.height += 2 * _BorderWidth();
987 if (containerSize.width > size.width)
988 size.width = containerSize.width;
989 size.height += containerSize.height;
991 return BLayoutUtils::ComposeSize(ExplicitMinSize(), size);
995 BSize
996 BTabView::MaxSize()
998 BSize size;
999 if (GetLayout())
1000 size = GetLayout()->MaxSize();
1001 else {
1002 size = _TabsMinSize();
1003 BSize containerSize = fContainerView->MaxSize();
1004 containerSize.width += 2 * _BorderWidth();
1005 containerSize.height += 2 * _BorderWidth();
1006 if (containerSize.width > size.width)
1007 size.width = containerSize.width;
1008 size.height += containerSize.height;
1010 return BLayoutUtils::ComposeSize(ExplicitMaxSize(), size);
1014 BSize
1015 BTabView::PreferredSize()
1017 BSize size;
1018 if (GetLayout() != NULL)
1019 size = GetLayout()->PreferredSize();
1020 else {
1021 size = _TabsMinSize();
1022 BSize containerSize = fContainerView->PreferredSize();
1023 containerSize.width += 2 * _BorderWidth();
1024 containerSize.height += 2 * _BorderWidth();
1025 if (containerSize.width > size.width)
1026 size.width = containerSize.width;
1027 size.height += containerSize.height;
1029 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), size);
1033 void
1034 BTabView::FrameMoved(BPoint newPosition)
1036 BView::FrameMoved(newPosition);
1040 void
1041 BTabView::FrameResized(float newWidth, float newHeight)
1043 BView::FrameResized(newWidth, newHeight);
1047 // #pragma mark -
1050 BHandler*
1051 BTabView::ResolveSpecifier(BMessage* message, int32 index,
1052 BMessage* specifier, int32 what, const char* property)
1054 BPropertyInfo propInfo(sPropertyList);
1056 if (propInfo.FindMatch(message, 0, specifier, what, property) >= B_OK)
1057 return this;
1059 return BView::ResolveSpecifier(message, index, specifier, what, property);
1063 status_t
1064 BTabView::GetSupportedSuites(BMessage* message)
1066 message->AddString("suites", "suite/vnd.Be-tab-view");
1068 BPropertyInfo propInfo(sPropertyList);
1069 message->AddFlat("messages", &propInfo);
1071 return BView::GetSupportedSuites(message);
1075 // #pragma mark -
1078 void
1079 BTabView::AddTab(BView* target, BTab* tab)
1081 if (tab == NULL)
1082 tab = new BTab(target);
1083 else
1084 tab->SetView(target);
1086 if (fContainerView->GetLayout())
1087 fContainerView->GetLayout()->AddView(CountTabs(), target);
1089 fTabList->AddItem(tab);
1090 BTab::Private(tab).SetTabView(this);
1092 // When we haven't had a any tabs before, but are already attached to the
1093 // window, select this one.
1094 if (CountTabs() == 1 && Window() != NULL)
1095 Select(0);
1099 BTab*
1100 BTabView::RemoveTab(int32 index)
1102 if (index < 0 || index >= CountTabs())
1103 return NULL;
1105 BTab* tab = (BTab*)fTabList->RemoveItem(index);
1106 if (tab == NULL)
1107 return NULL;
1109 tab->Deselect();
1110 BTab::Private(tab).SetTabView(NULL);
1112 if (fContainerView->GetLayout())
1113 fContainerView->GetLayout()->RemoveItem(index);
1115 if (CountTabs() == 0)
1116 fFocus = -1;
1117 else if (index <= fSelection)
1118 Select(fSelection - 1);
1120 if (fFocus == CountTabs() - 1 || CountTabs() == 0)
1121 SetFocusTab(fFocus, false);
1122 else
1123 SetFocusTab(fFocus, true);
1125 return tab;
1129 BTab*
1130 BTabView::TabAt(int32 index) const
1132 return (BTab*)fTabList->ItemAt(index);
1136 void
1137 BTabView::SetTabWidth(button_width width)
1139 fTabWidthSetting = width;
1141 Invalidate();
1145 button_width
1146 BTabView::TabWidth() const
1148 return fTabWidthSetting;
1152 void
1153 BTabView::SetTabHeight(float height)
1155 if (fTabHeight == height)
1156 return;
1158 fTabHeight = height;
1159 _LayoutContainerView(GetLayout() != NULL);
1161 Invalidate();
1165 float
1166 BTabView::TabHeight() const
1168 return fTabHeight;
1172 void
1173 BTabView::SetBorder(border_style border)
1175 if (fBorderStyle == border)
1176 return;
1178 fBorderStyle = border;
1180 _LayoutContainerView((Flags() & B_SUPPORTS_LAYOUT) != 0);
1184 border_style
1185 BTabView::Border() const
1187 return fBorderStyle;
1191 BView*
1192 BTabView::ContainerView() const
1194 return fContainerView;
1198 int32
1199 BTabView::CountTabs() const
1201 return fTabList->CountItems();
1205 BView*
1206 BTabView::ViewForTab(int32 tabIndex) const
1208 BTab* tab = TabAt(tabIndex);
1209 if (tab != NULL)
1210 return tab->View();
1212 return NULL;
1216 void
1217 BTabView::_InitObject(bool layouted, button_width width)
1219 fTabList = new BList;
1221 fTabWidthSetting = width;
1222 fSelection = -1;
1223 fFocus = -1;
1224 fTabOffset = 0.0f;
1225 fBorderStyle = B_FANCY_BORDER;
1227 rgb_color color = ui_color(B_PANEL_BACKGROUND_COLOR);
1229 SetViewColor(color);
1230 SetLowColor(color);
1232 font_height fh;
1233 GetFontHeight(&fh);
1234 fTabHeight = fh.ascent + fh.descent + fh.leading + 8.0f;
1236 fContainerView = NULL;
1237 _InitContainerView(layouted);
1241 void
1242 BTabView::_InitContainerView(bool layouted)
1244 bool needsLayout = false;
1245 bool createdContainer = false;
1246 if (layouted) {
1247 if (GetLayout() == NULL) {
1248 SetLayout(new(nothrow) BGroupLayout(B_HORIZONTAL));
1249 needsLayout = true;
1252 if (fContainerView == NULL) {
1253 fContainerView = new BView("view container", B_WILL_DRAW);
1254 fContainerView->SetLayout(new(std::nothrow) BCardLayout());
1255 createdContainer = true;
1257 } else if (fContainerView == NULL) {
1258 fContainerView = new BView(Bounds(), "view container", B_FOLLOW_ALL,
1259 B_WILL_DRAW);
1260 createdContainer = true;
1263 if (needsLayout || createdContainer)
1264 _LayoutContainerView(layouted);
1266 if (createdContainer) {
1267 fContainerView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
1268 fContainerView->SetLowColor(fContainerView->ViewColor());
1269 AddChild(fContainerView);
1274 BSize
1275 BTabView::_TabsMinSize() const
1277 BSize size(0.0f, TabHeight());
1278 int32 count = min_c(2, CountTabs());
1279 for (int32 i = 0; i < count; i++) {
1280 BRect frame = TabFrame(i);
1281 size.width += frame.Width();
1284 if (count < CountTabs()) {
1285 // TODO: Add size for yet to be implemented buttons that allow
1286 // "scrolling" the displayed tabs left/right.
1289 return size;
1293 float
1294 BTabView::_BorderWidth() const
1296 switch (fBorderStyle) {
1297 default:
1298 case B_FANCY_BORDER:
1299 return 3.0f;
1300 case B_PLAIN_BORDER:
1301 return 1.0f;
1302 case B_NO_BORDER:
1303 return 0.0f;
1308 void
1309 BTabView::_LayoutContainerView(bool layouted)
1311 float borderWidth = _BorderWidth();
1312 if (layouted) {
1313 float topBorderOffset;
1314 switch (fBorderStyle) {
1315 default:
1316 case B_FANCY_BORDER:
1317 topBorderOffset = 1.0f;
1318 break;
1319 case B_PLAIN_BORDER:
1320 topBorderOffset = 0.0f;
1321 break;
1322 case B_NO_BORDER:
1323 topBorderOffset = -1.0f;
1324 break;
1326 BGroupLayout* layout = dynamic_cast<BGroupLayout*>(GetLayout());
1327 if (layout != NULL) {
1328 layout->SetInsets(borderWidth, borderWidth + TabHeight()
1329 - topBorderOffset, borderWidth, borderWidth);
1331 } else {
1332 BRect bounds = Bounds();
1334 bounds.top += TabHeight();
1335 bounds.InsetBy(borderWidth, borderWidth);
1337 fContainerView->MoveTo(bounds.left, bounds.top);
1338 fContainerView->ResizeTo(bounds.Width(), bounds.Height());
1343 // #pragma mark - FBC and forbidden
1346 void BTabView::_ReservedTabView2() {}
1347 void BTabView::_ReservedTabView3() {}
1348 void BTabView::_ReservedTabView4() {}
1349 void BTabView::_ReservedTabView5() {}
1350 void BTabView::_ReservedTabView6() {}
1351 void BTabView::_ReservedTabView7() {}
1352 void BTabView::_ReservedTabView8() {}
1353 void BTabView::_ReservedTabView9() {}
1354 void BTabView::_ReservedTabView10() {}
1355 void BTabView::_ReservedTabView11() {}
1356 void BTabView::_ReservedTabView12() {}
1359 BTabView::BTabView(const BTabView& tabView)
1360 : BView(tabView)
1362 // this is private and not functional, but exported
1366 BTabView&
1367 BTabView::operator=(const BTabView&)
1369 // this is private and not functional, but exported
1370 return *this;
1373 // #pragma mark - binary compatibility
1376 extern "C" void
1377 B_IF_GCC_2(_ReservedTabView1__8BTabView, _ZN8BTabView17_ReservedTabView1Ev)(
1378 BTabView* tabView, border_style border)
1380 tabView->BTabView::SetBorder(border);