xref: /haiku/src/kits/interface/TabView.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
1 //------------------------------------------------------------------------------
2 //	Copyright (c) 2001-2005, Haiku
3 //
4 //	Permission is hereby granted, free of charge, to any person obtaining a
5 //	copy of this software and associated documentation files (the "Software"),
6 //	to deal in the Software without restriction, including without limitation
7 //	the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 //	and/or sell copies of the Software, and to permit persons to whom the
9 //	Software is furnished to do so, subject to the following conditions:
10 //
11 //	The above copyright notice and this permission notice shall be included in
12 //	all copies or substantial portions of the Software.
13 //
14 //	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 //	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 //	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 //	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 //	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 //	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 //	DEALINGS IN THE SOFTWARE.
21 //
22 //	File Name:		TabView.cpp
23 //	Author:			Marc Flerackers (mflerackers@androme.be)
24 //	Description:	BTab creates individual "tabs" that can be assigned
25 //                  to specific views.
26 //                  BTabView provides the framework for containing and
27 //                  managing groups of BTab objects.
28 //------------------------------------------------------------------------------
29 
30 #include <TabView.h>
31 #include <Message.h>
32 #include <List.h>
33 #include <Rect.h>
34 //#include <Errors.h>
35 
36 
37 BTab::BTab(BView *tabView)
38 	:
39 	fEnabled(true),
40 	fSelected(false),
41 	fFocus(false),
42 	fView(tabView)
43 {
44 }
45 
46 
47 BTab::BTab(BMessage *archive)
48 	:
49 	fSelected(false),
50 	fFocus(false),
51 	fView(NULL)
52 {
53 	bool disable;
54 
55 	if (archive->FindBool("_disable", &disable) != B_OK)
56 		SetEnabled(true);
57 	else
58 		SetEnabled(!disable);
59 }
60 
61 
62 BTab::~BTab()
63 {
64 	if (!fView)
65 		return;
66 
67 	if (fSelected)
68 		fView->RemoveSelf();
69 
70 	delete fView;
71 }
72 
73 
74 BArchivable *
75 BTab::Instantiate(BMessage *archive)
76 {
77 	if (validate_instantiation(archive, "BTab"))
78 		return new BTab(archive);
79 
80 	return NULL;
81 }
82 
83 
84 status_t
85 BTab::Archive(BMessage *archive, bool deep) const
86 {
87 	status_t err = BArchivable::Archive(archive, deep);
88 	if (err != B_OK)
89 		return err;
90 
91 	if (!fEnabled)
92 		err = archive->AddBool("_disable", false);
93 
94 	return err;
95 }
96 
97 
98 status_t
99 BTab::Perform(uint32 d, void *arg)
100 {
101 	return BArchivable::Perform(d, arg);
102 }
103 
104 
105 const char *
106 BTab::Label() const
107 {
108 	if (fView)
109 		return fView->Name();
110 	else
111 		return NULL;
112 }
113 
114 
115 void
116 BTab::SetLabel(const char *label)
117 {
118 	if (!label || !fView)
119 		return;
120 
121 	fView->SetName(label);
122 }
123 
124 
125 bool
126 BTab::IsSelected() const
127 {
128 	return fSelected;
129 }
130 
131 
132 void
133 BTab::Select(BView *owner)
134 {
135 	if (!owner || !View() || !owner->Window())
136 		return;
137 
138 	owner->AddChild(fView);
139 	//fView->Show();
140 
141 	fSelected = true;
142 }
143 
144 
145 void
146 BTab::Deselect()
147 {
148 	if (View())
149 		View()->RemoveSelf();
150 
151 	fSelected = false;
152 }
153 
154 
155 void
156 BTab::SetEnabled(bool enabled)
157 {
158 	fEnabled = enabled;
159 }
160 
161 
162 bool
163 BTab::IsEnabled() const
164 {
165 	return fEnabled;
166 }
167 
168 
169 void
170 BTab::MakeFocus(bool inFocus)
171 {
172 	fFocus = inFocus;
173 }
174 
175 
176 bool
177 BTab::IsFocus() const
178 {
179 	return fFocus;
180 }
181 
182 
183 void
184 BTab::SetView(BView *view)
185 {
186 	if (!view || fView == view)
187 		return;
188 
189 	if (fView != NULL) {
190 		fView->RemoveSelf();
191 		delete fView;
192 	}
193 	fView = view;
194 }
195 
196 
197 BView *
198 BTab::View() const
199 {
200 	return fView;
201 }
202 
203 
204 void
205 BTab::DrawFocusMark(BView *owner, BRect frame)
206 {
207 	float width = owner->StringWidth(Label());
208 
209 	owner->SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
210 	// TODO: remove offset
211 	float offset = frame.Height() / 2.0;
212 	owner->StrokeLine(BPoint((frame.left + frame.right - width + offset) / 2.0, frame.bottom - 3),
213 					  BPoint((frame.left + frame.right + width + offset) / 2.0, frame.bottom - 3));
214 }
215 
216 
217 void
218 BTab::DrawLabel(BView *owner, BRect frame)
219 {
220 	const char *label = Label();
221 	if (label == NULL)
222 		return;
223 
224 	owner->SetHighColor(ui_color(B_CONTROL_TEXT_COLOR));
225 	float width = owner->StringWidth(label);
226 	// TODO: remove offset
227 	float offset = frame.Height() / 2.0;
228 	owner->DrawString(label, BPoint((frame.left + frame.right - width + offset) / 2.0,
229 									frame.bottom - 4.0f - 2.0f));
230 }
231 
232 
233 void
234 BTab::DrawTab(BView *owner, BRect frame, tab_position position, bool full)
235 {
236 	rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR);
237 	rgb_color lightenmax = tint_color(no_tint, B_LIGHTEN_MAX_TINT);
238 	rgb_color darken2 = tint_color(no_tint, B_DARKEN_2_TINT);
239 	rgb_color darken3 = tint_color(no_tint, B_DARKEN_3_TINT);
240 	rgb_color darken4 = tint_color(no_tint, B_DARKEN_4_TINT);
241 	rgb_color darkenmax = tint_color(no_tint, B_DARKEN_MAX_TINT);
242 
243 	owner->SetHighColor(darkenmax);
244 	owner->SetLowColor(no_tint);
245 	DrawLabel(owner, frame);
246 
247 	owner->SetDrawingMode(B_OP_OVER);
248 
249 	owner->BeginLineArray(12);
250 
251 	int32 slopeWidth = (int32)ceilf(frame.Height() / 2.0);
252 
253 	if (position != B_TAB_ANY) {
254 		// full height left side
255 		owner->AddLine(BPoint(frame.left, frame.bottom),
256 					   BPoint(frame.left + slopeWidth, frame.top), darken3);
257 		owner->AddLine(BPoint(frame.left, frame.bottom + 1),
258 					   BPoint(frame.left + slopeWidth, frame.top + 1), lightenmax);
259 	} else {
260 		// upper half of left side
261 		owner->AddLine(BPoint(frame.left + slopeWidth / 2, frame.bottom - slopeWidth),
262 					   BPoint(frame.left + slopeWidth, frame.top), darken3);
263 		owner->AddLine(BPoint(frame.left + slopeWidth / 2 + 2, frame.bottom - slopeWidth - 1),
264 					   BPoint(frame.left + slopeWidth, frame.top + 1), lightenmax);
265 	}
266 
267 	// lines along the top
268 	owner->AddLine(BPoint(frame.left + slopeWidth, frame.top),
269 				   BPoint(frame.right, frame.top), darken3);
270 	owner->AddLine(BPoint(frame.left + slopeWidth, frame.top + 1),
271 				   BPoint(frame.right, frame.top + 1), lightenmax);
272 
273 	if (full) {
274 		// full height right side
275 		owner->AddLine(BPoint(frame.right, frame.top),
276 					   BPoint(frame.right + slopeWidth + 2, frame.bottom), darken2);
277 		owner->AddLine(BPoint(frame.right, frame.top + 1),
278 					   BPoint(frame.right + slopeWidth + 1, frame.bottom), darken4);
279 	} else {
280 		// upper half of right side
281 		owner->AddLine(BPoint(frame.right, frame.top),
282 					   BPoint(frame.right + slopeWidth / 2 + 1,
283 					   		  frame.bottom - slopeWidth), darken2);
284 		owner->AddLine(BPoint(frame.right, frame.top + 1),
285 					   BPoint(frame.right + slopeWidth / 2,
286 					   		  frame.bottom - slopeWidth), darken4);
287 	}
288 
289 	owner->EndLineArray();
290 }
291 
292 
293 void BTab::_ReservedTab1() {}
294 void BTab::_ReservedTab2() {}
295 void BTab::_ReservedTab3() {}
296 void BTab::_ReservedTab4() {}
297 void BTab::_ReservedTab5() {}
298 void BTab::_ReservedTab6() {}
299 void BTab::_ReservedTab7() {}
300 void BTab::_ReservedTab8() {}
301 void BTab::_ReservedTab9() {}
302 void BTab::_ReservedTab10() {}
303 void BTab::_ReservedTab11() {}
304 void BTab::_ReservedTab12() {}
305 
306 BTab &BTab::operator=(const BTab &)
307 {
308 	// this is private and not functional, but exported
309 	return *this;
310 }
311 
312 
313 //	#pragma mark -
314 
315 
316 BTabView::BTabView(BRect frame, const char *name, button_width width,
317 	uint32 resizingMode, uint32 flags)
318 	: BView(frame, name, resizingMode, flags)
319 {
320 	SetFont(be_bold_font);
321 
322 	_InitObject();
323 
324 	fTabWidthSetting = width;
325 }
326 
327 
328 BTabView::~BTabView()
329 {
330 	for (int32 i = 0; i < CountTabs(); i++) {
331 		delete TabAt(i);
332 	}
333 
334 	delete fTabList;
335 }
336 
337 
338 BTabView::BTabView(BMessage *archive)
339 	: BView(archive),
340 	fFocus(-1)
341 {
342 	fContainerView = NULL;
343 	fTabList = new BList;
344 
345 	int16 width;
346 
347 	if (archive->FindInt16("_but_width", &width) == B_OK)
348 		fTabWidthSetting = (button_width)width;
349 	else
350 		fTabWidthSetting = B_WIDTH_AS_USUAL;
351 
352 	if (archive->FindFloat("_high", &fTabHeight) != B_OK) {
353 		font_height fh;
354 		GetFontHeight(&fh);
355 		fTabHeight = fh.ascent + fh.descent + fh.leading + 8.0f;
356 	}
357 
358 	fFocus = -1;
359 
360 	if (archive->FindInt32("_sel", &fSelection) != B_OK)
361 		fSelection = 0;
362 
363 	if (fContainerView == NULL)
364 		fContainerView = ChildAt(0);
365 
366 	int32 i = 0;
367 	BMessage tabMsg;
368 
369 	while (archive->FindMessage("_l_items", i, &tabMsg) == B_OK) {
370 		BArchivable *archivedTab = instantiate_object(&tabMsg);
371 
372 		if (archivedTab) {
373 			BTab *tab = dynamic_cast<BTab *>(archivedTab);
374 
375 			BMessage viewMsg;
376 			if (archive->FindMessage("_view_list", i, &viewMsg) == B_OK) {
377 				BArchivable *archivedView = instantiate_object(&viewMsg);
378 				if (archivedView)
379 					AddTab(dynamic_cast<BView*>(archivedView), tab);
380 			}
381 		}
382 
383 		tabMsg.MakeEmpty();
384 		i++;
385 	}
386 }
387 
388 
389 BArchivable *
390 BTabView::Instantiate(BMessage *archive)
391 {
392 	if ( validate_instantiation(archive, "BTabView"))
393 		return new BTabView(archive);
394 
395 	return NULL;
396 }
397 
398 
399 status_t
400 BTabView::Archive(BMessage *archive, bool deep) const
401 {
402 	if (CountTabs() > 0)
403 		TabAt(Selection())->View()->RemoveSelf();
404 
405 	status_t ret = BView::Archive(archive, deep);
406 
407 	if (ret == B_OK)
408 		ret = archive->AddInt16("_but_width", fTabWidthSetting);
409 	if (ret == B_OK)
410 		ret = archive->AddFloat("_high", fTabHeight);
411 	if (ret == B_OK)
412 		ret = archive->AddInt32("_sel", fSelection);
413 
414 	if (ret == B_OK && deep) {
415 		for (int32 i = 0; i < CountTabs(); i++) {
416 			BMessage tabArchive;
417 			BTab *tab = TabAt(i);
418 
419 			if (!tab)
420 				continue;
421 			ret = tab->Archive(&tabArchive, true);
422 			if (ret == B_OK)
423 				ret = archive->AddMessage("_l_items", &tabArchive);
424 
425 			if (!tab->View())
426 				continue;
427 
428 			BMessage viewArchive;
429 			ret = tab->View()->Archive(&viewArchive, true);
430 			if (ret == B_OK)
431 				ret = archive->AddMessage("_view_list", &viewArchive);
432 		}
433 	}
434 
435 	if (CountTabs() > 0) {
436 		if (TabAt(Selection())->View() && ContainerView())
437 			TabAt(Selection())->Select(ContainerView());
438 	}
439 
440 	return ret;
441 }
442 
443 
444 status_t
445 BTabView::Perform(perform_code d, void *arg)
446 {
447 	return BView::Perform(d, arg);
448 }
449 
450 
451 void
452 BTabView::WindowActivated(bool active)
453 {
454 	BView::WindowActivated(active);
455 
456 	if (IsFocus())
457 		Invalidate();
458 }
459 
460 
461 void
462 BTabView::AttachedToWindow()
463 {
464 	BView::AttachedToWindow();
465 
466 	Select(fSelection);
467 }
468 
469 
470 void
471 BTabView::AllAttached()
472 {
473 	BView::AllAttached();
474 }
475 
476 
477 void
478 BTabView::AllDetached()
479 {
480 	BView::AllDetached();
481 }
482 
483 
484 void
485 BTabView::DetachedFromWindow()
486 {
487 	BView::DetachedFromWindow();
488 }
489 
490 
491 void
492 BTabView::MessageReceived(BMessage *message)
493 {
494 	BView::MessageReceived(message);
495 }
496 
497 
498 void
499 BTabView::FrameMoved(BPoint newLocation)
500 {
501 	BView::FrameMoved(newLocation);
502 }
503 
504 
505 void
506 BTabView::FrameResized(float width,float height)
507 {
508 	BView::FrameResized(width, height);
509 }
510 
511 
512 void
513 BTabView::KeyDown(const char *bytes, int32 numBytes)
514 {
515 	if (IsHidden())
516 		return;
517 
518 	switch (bytes[0]) {
519 		case B_DOWN_ARROW:
520 		case B_LEFT_ARROW: {
521 			int32 focus = fFocus - 1;
522 			if (focus < 0)
523 				focus = CountTabs() - 1;
524 			SetFocusTab(focus, true);
525 			break;
526 		}
527 
528 		case B_UP_ARROW:
529 		case B_RIGHT_ARROW: {
530 			int32 focus = fFocus + 1;
531 			if (focus >= CountTabs())
532 				focus = 0;
533 			SetFocusTab(focus, true);
534 			break;
535 		}
536 
537 		case B_RETURN:
538 		case B_SPACE:
539 			Select(FocusTab());
540 			break;
541 
542 		default:
543 			BView::KeyDown(bytes, numBytes);
544 	}
545 }
546 
547 
548 void
549 BTabView::MouseDown(BPoint point)
550 {
551 	if (point.y > fTabHeight)
552 		return;
553 
554 	for (int32 i = 0; i < CountTabs(); i++) {
555 		if (TabFrame(i).Contains(point)
556 			&& i != Selection()) {
557 			Select(i);
558 			return;
559 		}
560 	}
561 
562 	BView::MouseDown(point);
563 }
564 
565 
566 void
567 BTabView::MouseUp(BPoint point)
568 {
569 	BView::MouseUp(point);
570 }
571 
572 
573 void
574 BTabView::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
575 {
576 	BView::MouseMoved(point, transit, message);
577 }
578 
579 
580 void
581 BTabView::Pulse()
582 {
583 	BView::Pulse();
584 }
585 
586 
587 void
588 BTabView::Select(int32 index)
589 {
590 	if (index < 0 || index >= CountTabs())
591 		index = Selection();
592 
593 	BTab *tab = TabAt(Selection());
594 	if (tab)
595 		tab->Deselect();
596 
597 	tab = TabAt(index);
598 	if (tab && ContainerView()) {
599 		tab->Select(ContainerView());
600 		fSelection = index;
601 	}
602 
603 	Invalidate();
604 }
605 
606 
607 int32
608 BTabView::Selection() const
609 {
610 	return fSelection;
611 }
612 
613 
614 void
615 BTabView::MakeFocus(bool focused)
616 {
617 	BView::MakeFocus(focused);
618 
619 	SetFocusTab(Selection(), focused);
620 }
621 
622 
623 void
624 BTabView::SetFocusTab(int32 tab, bool focused)
625 {
626 	if (tab >= CountTabs())
627 		return;
628 
629 	if (focused) {
630 		if (tab == fFocus)
631 			return;
632 
633 		if (fFocus != -1){
634 			TabAt(fFocus)->MakeFocus(false);
635 			Invalidate(TabFrame(fFocus));
636 		}
637 		if (tab != -1) {
638 			TabAt(tab)->MakeFocus(true);
639 			Invalidate(TabFrame(tab));
640 		}
641 
642 		fFocus = tab;
643 	} else if (fFocus != -1) {
644 		TabAt(fFocus)->MakeFocus(false);
645 		Invalidate(TabFrame(fFocus));
646 //		fFocus = -1;
647 	}
648 }
649 
650 
651 int32
652 BTabView::FocusTab() const
653 {
654 	return fFocus;
655 }
656 
657 
658 void
659 BTabView::Draw(BRect updateRect)
660 {
661 	DrawBox(DrawTabs());
662 
663 	if (IsFocus() && fFocus != -1)
664 		TabAt(fFocus)->DrawFocusMark(this, TabFrame(fFocus));
665 }
666 
667 
668 BRect
669 BTabView::DrawTabs()
670 {
671 	for (int32 i = 0; i < CountTabs(); i++) {
672 		TabAt(i)->DrawTab(this, TabFrame(i),
673 			i == fSelection ? B_TAB_FRONT : (i == 0) ? B_TAB_FIRST : B_TAB_ANY,
674 			i + 1 != fSelection);
675 	}
676 
677 	if (fSelection < CountTabs())
678 		return TabFrame(fSelection);
679 
680 	return BRect();
681 }
682 
683 
684 void
685 BTabView::DrawBox(BRect selTabRect)
686 {
687 	BRect rect = Bounds();
688 	BRect lastTabRect = TabFrame(CountTabs() - 1);
689 
690 	rgb_color noTint = ui_color(B_PANEL_BACKGROUND_COLOR);
691 	rgb_color lightenMax = tint_color(noTint, B_LIGHTEN_MAX_TINT);
692 	rgb_color darken1 = tint_color(noTint, B_DARKEN_1_TINT);
693 	rgb_color darken2 = tint_color(noTint, B_DARKEN_2_TINT);
694 	rgb_color darken4 = tint_color(noTint, B_DARKEN_4_TINT);
695 
696 	BeginLineArray(12);
697 
698 	int32 offset = (int32)ceilf(selTabRect.Height() / 2.0);
699 
700 	// outer lines
701 	AddLine(BPoint(rect.left, rect.bottom - 1),
702 			BPoint(rect.left, selTabRect.bottom), darken2);
703 	if (selTabRect.left >= rect.left + 1)
704 		AddLine(BPoint(rect.left + 1, selTabRect.bottom),
705 				BPoint(selTabRect.left, selTabRect.bottom), darken2);
706 	if (lastTabRect.right + offset + 1 <= rect.right - 1)
707 		AddLine(BPoint(lastTabRect.right + offset + 1, selTabRect.bottom),
708 				BPoint(rect.right - 1, selTabRect.bottom), darken2);
709 	AddLine(BPoint(rect.right, selTabRect.bottom + 2),
710 			BPoint(rect.right, rect.bottom), darken2);
711 	AddLine(BPoint(rect.right - 1, rect.bottom),
712 			BPoint(rect.left + 2, rect.bottom), darken2);
713 
714 	// inner lines
715 	rect.InsetBy(1, 1);
716 	selTabRect.bottom += 1;
717 
718 	AddLine(BPoint(rect.left, rect.bottom - 2),
719 			BPoint(rect.left, selTabRect.bottom), lightenMax);
720 	if (selTabRect.left >= rect.left + 1)
721 		AddLine(BPoint(rect.left + 1, selTabRect.bottom),
722 				BPoint(selTabRect.left, selTabRect.bottom), lightenMax);
723 	if (selTabRect.right + offset + 1 <= rect.right - 2)
724 		AddLine(BPoint(selTabRect.right + offset + 1, selTabRect.bottom),
725 				BPoint(rect.right - 2, selTabRect.bottom), lightenMax);
726 	AddLine(BPoint(rect.right, selTabRect.bottom),
727 			BPoint(rect.right, rect.bottom), darken4);
728 	AddLine(BPoint(rect.right - 1, rect.bottom),
729 			BPoint(rect.left, rect.bottom), darken4);
730 
731 	// soft inner bevel at right/bottom
732 	rect.right--;
733 	rect.bottom--;
734 
735 	AddLine(BPoint(rect.right, selTabRect.bottom + 1),
736 			BPoint(rect.right, rect.bottom), darken1);
737 	AddLine(BPoint(rect.right - 1, rect.bottom),
738 			BPoint(rect.left + 1, rect.bottom), darken1);
739 
740 	EndLineArray();
741 }
742 
743 #define X_OFFSET 0.0f
744 
745 BRect
746 BTabView::TabFrame(int32 tab_index) const
747 {
748 	// TODO: fix to remove "offset" in DrawTab and DrawLabel ...
749 	switch (fTabWidthSetting) {
750 		case B_WIDTH_FROM_LABEL:
751 		{
752 			float x = X_OFFSET;
753 			for (int32 i = 0; i < tab_index; i++)
754 				x += StringWidth(TabAt(i)->Label()) + 20.0f;
755 
756 			return BRect(x, 0.0f,
757 				x + StringWidth(TabAt(tab_index)->Label()) + 20.0f, fTabHeight);
758 		}
759 
760 		case B_WIDTH_FROM_WIDEST:
761 		{
762 			float width = 0.0f;
763 
764 			for (int32 i = 0; i < CountTabs(); i++) {
765 				float tabWidth = StringWidth(TabAt(i)->Label()) + 20.0f;
766 
767 				if (tabWidth > width)
768 					width = tabWidth;
769 			}
770 
771 			return BRect(X_OFFSET + tab_index * width, 0.0f,
772 				X_OFFSET + tab_index * width + width, fTabHeight);
773 		}
774 
775 		case B_WIDTH_AS_USUAL:
776 		default:
777 			return BRect(X_OFFSET + tab_index * 100.0f, 0.0f,
778 				X_OFFSET + tab_index * 100.0f + 100.0f, fTabHeight);
779 	}
780 }
781 
782 
783 void
784 BTabView::SetFlags(uint32 flags)
785 {
786 	BView::SetFlags(flags);
787 }
788 
789 
790 void
791 BTabView::SetResizingMode(uint32 mode)
792 {
793 	BView::SetResizingMode(mode);
794 }
795 
796 
797 void
798 BTabView::GetPreferredSize(float *width, float *height)
799 {
800 	BView::GetPreferredSize(width, height);
801 }
802 
803 
804 void
805 BTabView::ResizeToPreferred()
806 {
807 	BView::ResizeToPreferred();
808 }
809 
810 
811 BHandler *
812 BTabView::ResolveSpecifier(BMessage *message, int32 index,
813 	BMessage *specifier, int32 what, const char *property)
814 {
815 	return BView::ResolveSpecifier(message, index, specifier, what, property);
816 }
817 
818 
819 status_t
820 BTabView::GetSupportedSuites(BMessage *message)
821 {
822 	return BView::GetSupportedSuites(message);
823 }
824 
825 
826 void
827 BTabView::AddTab(BView *target, BTab *tab)
828 {
829 	if (tab == NULL)
830 		tab = new BTab(target);
831 	else
832 		tab->SetView(target);
833 
834 	fTabList->AddItem(tab);
835 }
836 
837 
838 BTab *
839 BTabView::RemoveTab(int32 index)
840 {
841 	if (index < 0 || index >= CountTabs())
842 		return NULL;
843 
844 	BTab *tab = (BTab *)fTabList->RemoveItem(index);
845 	if (tab == NULL)
846 		return NULL;
847 
848 	tab->Deselect();
849 
850 	if (index <= fSelection && fSelection != 0)
851 		fSelection--;
852 
853 	Select(fSelection);
854 
855 	if (fFocus == CountTabs() - 1)
856 		SetFocusTab(fFocus, false);
857 	else
858 		SetFocusTab(fFocus, true);
859 
860 	return tab;
861 }
862 
863 
864 BTab *
865 BTabView::TabAt(int32 index) const
866 {
867 	return (BTab *)fTabList->ItemAt(index);
868 }
869 
870 
871 void
872 BTabView::SetTabWidth(button_width width)
873 {
874 	fTabWidthSetting = width;
875 
876 	Invalidate();
877 }
878 
879 
880 button_width
881 BTabView::TabWidth() const
882 {
883 	return fTabWidthSetting;
884 }
885 
886 
887 void
888 BTabView::SetTabHeight(float height)
889 {
890 	if (fTabHeight == height)
891 		return;
892 
893 	fContainerView->MoveBy(0.0f, height - fTabHeight);
894 	fContainerView->ResizeBy(0.0f, height - fTabHeight);
895 
896 	fTabHeight = height;
897 
898 	Invalidate();
899 }
900 
901 
902 float
903 BTabView::TabHeight() const
904 {
905 	return fTabHeight;
906 }
907 
908 
909 BView *
910 BTabView::ContainerView() const
911 {
912 	return fContainerView;
913 }
914 
915 
916 int32
917 BTabView::CountTabs() const
918 {
919 	return fTabList->CountItems();
920 }
921 
922 
923 BView *
924 BTabView::ViewForTab(int32 tabIndex) const
925 {
926 	BTab *tab = TabAt(tabIndex);
927 	if (tab)
928 		return tab->View();
929 
930 	return NULL;
931 }
932 
933 
934 void
935 BTabView::_InitObject()
936 {
937 	fTabList = new BList;
938 
939 	fTabWidthSetting = B_WIDTH_AS_USUAL;
940 	fSelection = 0;
941 	fFocus = -1;
942 
943 	rgb_color color = ui_color(B_PANEL_BACKGROUND_COLOR);
944 
945 	SetViewColor(color);
946 	SetLowColor(color);
947 
948 	font_height fh;
949 	GetFontHeight(&fh);
950 	fTabHeight = fh.ascent + fh.descent + fh.leading + 8.0f;
951 
952 	BRect bounds = Bounds();
953 
954 	bounds.top += TabHeight();
955 	bounds.InsetBy(3.0f, 3.0f);
956 
957 	fContainerView = new BView(bounds, "view container", B_FOLLOW_ALL,
958 		B_WILL_DRAW);
959 
960 	fContainerView->SetViewColor(color);
961 	fContainerView->SetLowColor(color);
962 
963 	AddChild(fContainerView);
964 }
965 
966 
967 void BTabView::_ReservedTabView1() {}
968 void BTabView::_ReservedTabView2() {}
969 void BTabView::_ReservedTabView3() {}
970 void BTabView::_ReservedTabView4() {}
971 void BTabView::_ReservedTabView5() {}
972 void BTabView::_ReservedTabView6() {}
973 void BTabView::_ReservedTabView7() {}
974 void BTabView::_ReservedTabView8() {}
975 void BTabView::_ReservedTabView9() {}
976 void BTabView::_ReservedTabView10() {}
977 void BTabView::_ReservedTabView11() {}
978 void BTabView::_ReservedTabView12() {}
979 
980 
981 BTabView::BTabView(const BTabView &tabView)
982 	: BView(tabView)
983 {
984 	// this is private and not functional, but exported
985 }
986 
987 
988 BTabView &BTabView::operator=(const BTabView &)
989 {
990 	// this is private and not functional, but exported
991 	return *this;
992 }
993