Ticket #2198: TabView.cpp.Invoker

File TabView.cpp.Invoker, 21.1 KB (added by shinta, 16 years ago)
Line 
1/*
2 * Copyright (c) 2001-2008, Haiku, Inc.
3 * Distributed under the terms of the MIT license.
4 *
5 * Authors:
6 * Marc Flerackers (mflerackers@androme.be)
7 * Jérôme Duval (korli@users.berlios.de)
8 */
9#include <TabView.h>
10
11#include <string.h>
12
13#include <List.h>
14#include <Message.h>
15#include <PropertyInfo.h>
16#include <Rect.h>
17#include <String.h>
18
19
20static property_info sPropertyList[] = {
21 {
22 "Selection",
23 { B_GET_PROPERTY, B_SET_PROPERTY },
24 { B_DIRECT_SPECIFIER },
25 NULL, 0,
26 { B_INT32_TYPE }
27 },
28 {}
29};
30
31
32
33BTab::BTab(BView *tabView)
34 :
35 fEnabled(true),
36 fSelected(false),
37 fFocus(false),
38 fView(tabView)
39{
40}
41
42
43BTab::BTab(BMessage *archive)
44 :
45 fSelected(false),
46 fFocus(false),
47 fView(NULL)
48{
49 bool disable;
50
51 if (archive->FindBool("_disable", &disable) != B_OK)
52 SetEnabled(true);
53 else
54 SetEnabled(!disable);
55}
56
57
58BTab::~BTab()
59{
60 if (!fView)
61 return;
62
63 if (fSelected)
64 fView->RemoveSelf();
65
66 delete fView;
67}
68
69
70BArchivable *
71BTab::Instantiate(BMessage *archive)
72{
73 if (validate_instantiation(archive, "BTab"))
74 return new BTab(archive);
75
76 return NULL;
77}
78
79
80status_t
81BTab::Archive(BMessage *archive, bool deep) const
82{
83 status_t err = BArchivable::Archive(archive, deep);
84 if (err != B_OK)
85 return err;
86
87 if (!fEnabled)
88 err = archive->AddBool("_disable", false);
89
90 return err;
91}
92
93
94status_t
95BTab::Perform(uint32 d, void *arg)
96{
97 return BArchivable::Perform(d, arg);
98}
99
100
101const char *
102BTab::Label() const
103{
104 if (fView)
105 return fView->Name();
106 else
107 return NULL;
108}
109
110
111void
112BTab::SetLabel(const char *label)
113{
114 if (!label || !fView)
115 return;
116
117 fView->SetName(label);
118}
119
120
121bool
122BTab::IsSelected() const
123{
124 return fSelected;
125}
126
127
128void
129BTab::Select(BView *owner)
130{
131 if (!owner || !View() || !owner->Window())
132 return;
133
134 owner->AddChild(fView);
135 //fView->Show();
136
137 fSelected = true;
138}
139
140
141void
142BTab::Deselect()
143{
144 if (View())
145 View()->RemoveSelf();
146
147 fSelected = false;
148}
149
150
151void
152BTab::SetEnabled(bool enabled)
153{
154 fEnabled = enabled;
155}
156
157
158bool
159BTab::IsEnabled() const
160{
161 return fEnabled;
162}
163
164
165void
166BTab::MakeFocus(bool inFocus)
167{
168 fFocus = inFocus;
169}
170
171
172bool
173BTab::IsFocus() const
174{
175 return fFocus;
176}
177
178
179void
180BTab::SetView(BView *view)
181{
182 if (!view || fView == view)
183 return;
184
185 if (fView != NULL) {
186 fView->RemoveSelf();
187 delete fView;
188 }
189 fView = view;
190}
191
192
193BView *
194BTab::View() const
195{
196 return fView;
197}
198
199
200void
201BTab::DrawFocusMark(BView *owner, BRect frame)
202{
203 float width = owner->StringWidth(Label());
204
205 owner->SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
206 // TODO: remove offset
207 float offset = frame.Height() / 2.0;
208 owner->StrokeLine(BPoint((frame.left + frame.right - width + offset) / 2.0,
209 frame.bottom - 3),
210 BPoint((frame.left + frame.right + width + offset) / 2.0,
211 frame.bottom - 3));
212}
213
214
215void
216BTab::DrawLabel(BView *owner, BRect frame)
217{
218 if (Label() == NULL)
219 return;
220
221 BString label = Label();
222 float frameWidth = frame.Width();
223 float width = owner->StringWidth(label.String());
224 font_height fh;
225
226 if (width > frameWidth) {
227 BFont font;
228 owner->GetFont(&font);
229 font.TruncateString(&label, B_TRUNCATE_END, frameWidth);
230 width = frameWidth;
231 font.GetHeight(&fh);
232 } else {
233 owner->GetFontHeight(&fh);
234 }
235
236 owner->SetHighColor(ui_color(B_CONTROL_TEXT_COLOR));
237 owner->DrawString(label.String(),
238 BPoint((frame.left + frame.right - width) / 2.0,
239 (frame.top + frame.bottom - fh.ascent - fh.descent) / 2.0
240 + fh.ascent));
241}
242
243
244void
245BTab::DrawTab(BView *owner, BRect frame, tab_position position, bool full)
246{
247 rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR);
248 rgb_color lightenmax = tint_color(no_tint, B_LIGHTEN_MAX_TINT);
249 rgb_color darken2 = tint_color(no_tint, B_DARKEN_2_TINT);
250 rgb_color darken3 = tint_color(no_tint, B_DARKEN_3_TINT);
251 rgb_color darken4 = tint_color(no_tint, B_DARKEN_4_TINT);
252 rgb_color darkenmax = tint_color(no_tint, B_DARKEN_MAX_TINT);
253
254 owner->SetHighColor(darkenmax);
255 owner->SetLowColor(no_tint);
256 // NOTE: "frame" goes from the beginning of the left slope to the beginning
257 // of the right slope - "lableFrame" is the frame between both slopes
258 BRect lableFrame = frame;
259 lableFrame.left = lableFrame.left + frame.Height() / 2.0;
260 DrawLabel(owner, lableFrame);
261
262 owner->SetDrawingMode(B_OP_OVER);
263
264 owner->BeginLineArray(12);
265
266 int32 slopeWidth = (int32)ceilf(frame.Height() / 2.0);
267
268 if (position != B_TAB_ANY) {
269 // full height left side
270 owner->AddLine(BPoint(frame.left, frame.bottom),
271 BPoint(frame.left + slopeWidth, frame.top), darken3);
272 owner->AddLine(BPoint(frame.left, frame.bottom + 1),
273 BPoint(frame.left + slopeWidth, frame.top + 1), lightenmax);
274 } else {
275 // upper half of left side
276 owner->AddLine(BPoint(frame.left + slopeWidth / 2,
277 frame.bottom - slopeWidth),
278 BPoint(frame.left + slopeWidth, frame.top), darken3);
279 owner->AddLine(BPoint(frame.left + slopeWidth / 2 + 2,
280 frame.bottom - slopeWidth - 1),
281 BPoint(frame.left + slopeWidth, frame.top + 1), lightenmax);
282 }
283
284 // lines along the top
285 owner->AddLine(BPoint(frame.left + slopeWidth, frame.top),
286 BPoint(frame.right, frame.top), darken3);
287 owner->AddLine(BPoint(frame.left + slopeWidth, frame.top + 1),
288 BPoint(frame.right, frame.top + 1), lightenmax);
289
290 if (full) {
291 // full height right side
292 owner->AddLine(BPoint(frame.right, frame.top),
293 BPoint(frame.right + slopeWidth + 2, frame.bottom), darken2);
294 owner->AddLine(BPoint(frame.right, frame.top + 1),
295 BPoint(frame.right + slopeWidth + 1, frame.bottom), darken4);
296 } else {
297 // upper half of right side
298 owner->AddLine(BPoint(frame.right, frame.top),
299 BPoint(frame.right + slopeWidth / 2 + 1,
300 frame.bottom - slopeWidth), darken2);
301 owner->AddLine(BPoint(frame.right, frame.top + 1),
302 BPoint(frame.right + slopeWidth / 2,
303 frame.bottom - slopeWidth), darken4);
304 }
305
306 owner->EndLineArray();
307}
308
309
310void BTab::_ReservedTab1() {}
311void BTab::_ReservedTab2() {}
312void BTab::_ReservedTab3() {}
313void BTab::_ReservedTab4() {}
314void BTab::_ReservedTab5() {}
315void BTab::_ReservedTab6() {}
316void BTab::_ReservedTab7() {}
317void BTab::_ReservedTab8() {}
318void BTab::_ReservedTab9() {}
319void BTab::_ReservedTab10() {}
320void BTab::_ReservedTab11() {}
321void BTab::_ReservedTab12() {}
322
323BTab &BTab::operator=(const BTab &)
324{
325 // this is private and not functional, but exported
326 return *this;
327}
328
329
330// #pragma mark -
331
332
333BTabView::BTabView(BRect frame, const char *name, button_width width,
334 uint32 resizingMode, uint32 flags)
335 : BView(frame, name, resizingMode, flags)
336{
337 SetFont(be_bold_font);
338
339 _InitObject();
340
341 fTabWidthSetting = width;
342}
343
344
345BTabView::~BTabView()
346{
347 for (int32 i = 0; i < CountTabs(); i++) {
348 delete TabAt(i);
349 }
350
351 delete fTabList;
352}
353
354
355BTabView::BTabView(BMessage *archive)
356 : BView(archive),
357 fFocus(-1)
358{
359 fContainerView = NULL;
360 fTabList = new BList;
361
362 int16 width;
363
364 if (archive->FindInt16("_but_width", &width) == B_OK)
365 fTabWidthSetting = (button_width)width;
366 else
367 fTabWidthSetting = B_WIDTH_AS_USUAL;
368
369 if (archive->FindFloat("_high", &fTabHeight) != B_OK) {
370 font_height fh;
371 GetFontHeight(&fh);
372 fTabHeight = fh.ascent + fh.descent + fh.leading + 8.0f;
373 }
374
375 fFocus = -1;
376
377 if (archive->FindInt32("_sel", &fSelection) != B_OK)
378 fSelection = 0;
379
380 if (fContainerView == NULL)
381 fContainerView = ChildAt(0);
382
383 int32 i = 0;
384 BMessage tabMsg;
385
386 while (archive->FindMessage("_l_items", i, &tabMsg) == B_OK) {
387 BArchivable *archivedTab = instantiate_object(&tabMsg);
388
389 if (archivedTab) {
390 BTab *tab = dynamic_cast<BTab *>(archivedTab);
391
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);
397 }
398 }
399
400 tabMsg.MakeEmpty();
401 i++;
402 }
403}
404
405
406BArchivable *
407BTabView::Instantiate(BMessage *archive)
408{
409 if ( validate_instantiation(archive, "BTabView"))
410 return new BTabView(archive);
411
412 return NULL;
413}
414
415
416status_t
417BTabView::Archive(BMessage *archive, bool deep) const
418{
419 if (CountTabs() > 0)
420 TabAt(Selection())->View()->RemoveSelf();
421
422 status_t ret = BView::Archive(archive, deep);
423
424 if (ret == B_OK)
425 ret = archive->AddInt16("_but_width", fTabWidthSetting);
426 if (ret == B_OK)
427 ret = archive->AddFloat("_high", fTabHeight);
428 if (ret == B_OK)
429 ret = archive->AddInt32("_sel", fSelection);
430
431 if (ret == B_OK && deep) {
432 for (int32 i = 0; i < CountTabs(); i++) {
433 BMessage tabArchive;
434 BTab *tab = TabAt(i);
435
436 if (!tab)
437 continue;
438 ret = tab->Archive(&tabArchive, true);
439 if (ret == B_OK)
440 ret = archive->AddMessage("_l_items", &tabArchive);
441
442 if (!tab->View())
443 continue;
444
445 BMessage viewArchive;
446 ret = tab->View()->Archive(&viewArchive, true);
447 if (ret == B_OK)
448 ret = archive->AddMessage("_view_list", &viewArchive);
449 }
450 }
451
452 if (CountTabs() > 0) {
453 if (TabAt(Selection())->View() && ContainerView())
454 TabAt(Selection())->Select(ContainerView());
455 }
456
457 return ret;
458}
459
460
461status_t
462BTabView::Perform(perform_code d, void *arg)
463{
464 return BView::Perform(d, arg);
465}
466
467
468void
469BTabView::WindowActivated(bool active)
470{
471 BView::WindowActivated(active);
472
473 if (IsFocus())
474 Invalidate();
475}
476
477
478void
479BTabView::AttachedToWindow()
480{
481 BView::AttachedToWindow();
482
483 Select(fSelection);
484}
485
486
487void
488BTabView::AllAttached()
489{
490 BView::AllAttached();
491}
492
493
494void
495BTabView::AllDetached()
496{
497 BView::AllDetached();
498}
499
500
501void
502BTabView::DetachedFromWindow()
503{
504 BView::DetachedFromWindow();
505}
506
507
508void
509BTabView::MessageReceived(BMessage *message)
510{
511 switch (message->what) {
512 case B_GET_PROPERTY:
513 case B_SET_PROPERTY:
514 {
515 BMessage reply(B_REPLY);
516 bool handled = false;
517
518 BMessage specifier;
519 int32 index;
520 int32 form;
521 const char *property;
522 if (message->GetCurrentSpecifier(&index, &specifier, &form, &property) == B_OK) {
523 if (strcmp(property, "Selection") == 0) {
524 if (message->what == B_GET_PROPERTY) {
525 reply.AddInt32("result", fSelection);
526 handled = true;
527 } else {
528 // B_GET_PROPERTY
529 int32 selection;
530 if (message->FindInt32("data", &selection) == B_OK) {
531 Select(selection);
532 reply.AddInt32("error", B_OK);
533 handled = true;
534 }
535 }
536 }
537 }
538
539 if (handled)
540 message->SendReply(&reply);
541 else
542 BView::MessageReceived(message);
543 break;
544 }
545
546 case B_MOUSE_WHEEL_CHANGED:
547 {
548 float deltaX = 0.0f;
549 float deltaY = 0.0f;
550 message->FindFloat("be:wheel_delta_x", &deltaX);
551 message->FindFloat("be:wheel_delta_y", &deltaY);
552
553 if (deltaX == 0.0f && deltaY == 0.0f)
554 return;
555
556 if (deltaY == 0.0f)
557 deltaY = deltaX;
558
559 int32 selection = Selection();
560 int32 numTabs = CountTabs();
561 if (deltaY > 0 && selection < numTabs - 1) {
562 //move to the right tab.
563 Select(Selection() + 1);
564 } else if (deltaY < 0 && selection > 0 && numTabs > 1) {
565 //move to the left tab.
566 Select(selection - 1);
567 }
568 }
569 default:
570 BView::MessageReceived(message);
571 break;
572 }
573}
574
575
576void
577BTabView::FrameMoved(BPoint newLocation)
578{
579 BView::FrameMoved(newLocation);
580}
581
582
583void
584BTabView::FrameResized(float width,float height)
585{
586 BView::FrameResized(width, height);
587}
588
589
590void
591BTabView::KeyDown(const char *bytes, int32 numBytes)
592{
593 if (IsHidden())
594 return;
595
596 switch (bytes[0]) {
597 case B_DOWN_ARROW:
598 case B_LEFT_ARROW: {
599 int32 focus = fFocus - 1;
600 if (focus < 0)
601 focus = CountTabs() - 1;
602 SetFocusTab(focus, true);
603 break;
604 }
605
606 case B_UP_ARROW:
607 case B_RIGHT_ARROW: {
608 int32 focus = fFocus + 1;
609 if (focus >= CountTabs())
610 focus = 0;
611 SetFocusTab(focus, true);
612 break;
613 }
614
615 case B_RETURN:
616 case B_SPACE:
617 Select(FocusTab());
618 break;
619
620 default:
621 BView::KeyDown(bytes, numBytes);
622 }
623}
624
625
626void
627BTabView::MouseDown(BPoint point)
628{
629 if (point.y > fTabHeight)
630 return;
631
632 for (int32 i = 0; i < CountTabs(); i++) {
633 if (TabFrame(i).Contains(point)
634 && i != Selection()) {
635 Select(i);
636 return;
637 }
638 }
639
640 BView::MouseDown(point);
641}
642
643
644void
645BTabView::MouseUp(BPoint point)
646{
647 BView::MouseUp(point);
648}
649
650
651void
652BTabView::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
653{
654 BView::MouseMoved(point, transit, message);
655}
656
657
658void
659BTabView::Pulse()
660{
661 BView::Pulse();
662}
663
664
665void
666BTabView::Select(int32 index)
667{
668 if (index < 0 || index >= CountTabs())
669 index = Selection();
670
671 BTab *tab = TabAt(Selection());
672 if (tab)
673 tab->Deselect();
674
675 tab = TabAt(index);
676 if (tab && ContainerView()) {
677 if (index == 0)
678 fTabOffset = 0.0f;
679 tab->Select(ContainerView());
680 fSelection = index;
681 SelectionChanged();
682 InvokeNotify(Message(), B_CONTROL_MODIFIED);
683 }
684
685 Invalidate();
686
687 if (index != 0 && !Bounds().Contains(TabFrame(index))){
688 if (!Bounds().Contains(TabFrame(index).LeftTop()))
689 fTabOffset += TabFrame(index).left - Bounds().left - 20.0f;
690 else
691 fTabOffset += TabFrame(index).right - Bounds().right + 20.0f;
692
693 Invalidate();
694 }
695
696 /*MakeFocus();
697 SetFocusTab(index, true);
698 FocusTab();*/
699}
700
701
702int32
703BTabView::Selection() const
704{
705 return fSelection;
706}
707
708
709void
710BTabView::MakeFocus(bool focused)
711{
712 BView::MakeFocus(focused);
713
714 SetFocusTab(Selection(), focused);
715}
716
717
718void
719BTabView::SetFocusTab(int32 tab, bool focused)
720{
721 if (tab >= CountTabs())
722 tab = 0;
723
724 if (tab < 0)
725 tab = CountTabs() - 1;
726
727 if (focused) {
728 if (tab == fFocus)
729 return;
730
731 if (fFocus != -1){
732 if (TabAt (fFocus) != NULL)
733 TabAt(fFocus)->MakeFocus(false);
734 Invalidate(TabFrame(fFocus));
735 }
736 if (TabAt(tab) != NULL){
737 TabAt(tab)->MakeFocus(true);
738 Invalidate(TabFrame(tab));
739 fFocus = tab;
740 }
741 } else if (fFocus != -1) {
742 TabAt(fFocus)->MakeFocus(false);
743 Invalidate(TabFrame(fFocus));
744 fFocus = -1;
745 }
746}
747
748
749int32
750BTabView::FocusTab() const
751{
752 return fFocus;
753}
754
755
756void
757BTabView::Draw(BRect updateRect)
758{
759 DrawBox(DrawTabs());
760
761 if (IsFocus() && fFocus != -1)
762 TabAt(fFocus)->DrawFocusMark(this, TabFrame(fFocus));
763}
764
765
766BRect
767BTabView::DrawTabs()
768{
769 for (int32 i = 0; i < CountTabs(); i++) {
770 TabAt(i)->DrawTab(this, TabFrame(i),
771 i == fSelection ? B_TAB_FRONT : (i == 0) ? B_TAB_FIRST : B_TAB_ANY,
772 i + 1 != fSelection);
773 }
774
775 if (fSelection < CountTabs())
776 return TabFrame(fSelection);
777
778 return BRect();
779}
780
781
782void
783BTabView::DrawBox(BRect selTabRect)
784{
785 BRect rect = Bounds();
786 BRect lastTabRect = TabFrame(CountTabs() - 1);
787
788 rgb_color noTint = ui_color(B_PANEL_BACKGROUND_COLOR);
789 rgb_color lightenMax = tint_color(noTint, B_LIGHTEN_MAX_TINT);
790 rgb_color darken1 = tint_color(noTint, B_DARKEN_1_TINT);
791 rgb_color darken2 = tint_color(noTint, B_DARKEN_2_TINT);
792 rgb_color darken4 = tint_color(noTint, B_DARKEN_4_TINT);
793
794 BeginLineArray(12);
795
796 int32 offset = (int32)ceilf(selTabRect.Height() / 2.0);
797
798 // outer lines
799 AddLine(BPoint(rect.left, rect.bottom - 1),
800 BPoint(rect.left, selTabRect.bottom), darken2);
801 if (selTabRect.left >= rect.left + 1)
802 AddLine(BPoint(rect.left + 1, selTabRect.bottom),
803 BPoint(selTabRect.left, selTabRect.bottom), darken2);
804 if (lastTabRect.right + offset + 1 <= rect.right - 1)
805 AddLine(BPoint(lastTabRect.right + offset + 1, selTabRect.bottom),
806 BPoint(rect.right - 1, selTabRect.bottom), darken2);
807 AddLine(BPoint(rect.right, selTabRect.bottom + 2),
808 BPoint(rect.right, rect.bottom), darken2);
809 AddLine(BPoint(rect.right - 1, rect.bottom),
810 BPoint(rect.left + 2, rect.bottom), darken2);
811
812 // inner lines
813 rect.InsetBy(1, 1);
814 selTabRect.bottom += 1;
815
816 AddLine(BPoint(rect.left, rect.bottom - 2),
817 BPoint(rect.left, selTabRect.bottom), lightenMax);
818 if (selTabRect.left >= rect.left + 1)
819 AddLine(BPoint(rect.left + 1, selTabRect.bottom),
820 BPoint(selTabRect.left, selTabRect.bottom), lightenMax);
821 if (selTabRect.right + offset + 1 <= rect.right - 2)
822 AddLine(BPoint(selTabRect.right + offset + 1, selTabRect.bottom),
823 BPoint(rect.right - 2, selTabRect.bottom), lightenMax);
824 AddLine(BPoint(rect.right, selTabRect.bottom),
825 BPoint(rect.right, rect.bottom), darken4);
826 AddLine(BPoint(rect.right - 1, rect.bottom),
827 BPoint(rect.left, rect.bottom), darken4);
828
829 // soft inner bevel at right/bottom
830 rect.right--;
831 rect.bottom--;
832
833 AddLine(BPoint(rect.right, selTabRect.bottom + 1),
834 BPoint(rect.right, rect.bottom), darken1);
835 AddLine(BPoint(rect.right - 1, rect.bottom),
836 BPoint(rect.left + 1, rect.bottom), darken1);
837
838 EndLineArray();
839}
840
841#define X_OFFSET 0.0f
842
843BRect
844BTabView::TabFrame(int32 tab_index) const
845{
846 // TODO: fix to remove "offset" in DrawTab and DrawLabel ...
847 switch (fTabWidthSetting) {
848 case B_WIDTH_FROM_LABEL:
849 {
850 float x = 6.0f;
851 for (int32 i = 0; i < tab_index; i++){
852 x += StringWidth(TabAt(i)->Label()) + 20.0f;
853 }
854
855 return BRect(x - fTabOffset, 0.0f,
856 x - fTabOffset + StringWidth(TabAt(tab_index)->Label()) + 20.0f , fTabHeight);
857
858
859 /*float x = X_OFFSET;
860 for (int32 i = 0; i < tab_index; i++)
861 x += StringWidth(TabAt(i)->Label()) + 20.0f;
862
863 return BRect(x, 0.0f,
864 x + StringWidth(TabAt(tab_index)->Label()) + 20.0f, fTabHeight);*/
865 }
866
867 case B_WIDTH_FROM_WIDEST:
868 {
869 float width = 0.0f;
870
871 for (int32 i = 0; i < CountTabs(); i++) {
872 float tabWidth = StringWidth(TabAt(i)->Label()) + 20.0f;
873 if (tabWidth > width)
874 width = tabWidth;
875 }
876 return BRect((6.0f + tab_index * width) - fTabOffset, 0.0f,
877 (6.0f + tab_index * width + width) - fTabOffset, fTabHeight);
878 /*float width = 0.0f;
879
880 for (int32 i = 0; i < CountTabs(); i++) {
881 float tabWidth = StringWidth(TabAt(i)->Label()) + 20.0f;
882
883 if (tabWidth > width)
884 width = tabWidth;
885 }
886
887 return BRect(X_OFFSET + tab_index * width, 0.0f,
888 X_OFFSET + tab_index * width + width, fTabHeight);*/
889 }
890
891 case B_WIDTH_AS_USUAL:
892 default:
893 return BRect((6.0f + tab_index * 100.0f) - fTabOffset, 0.0f,
894 (6.0f + tab_index * 100.0f + 100.0f) - fTabOffset, fTabHeight);
895 /*return BRect(X_OFFSET + tab_index * 100.0f, 0.0f,
896 X_OFFSET + tab_index * 100.0f + 100.0f, fTabHeight);*/
897 }
898}
899
900
901void
902BTabView::SetFlags(uint32 flags)
903{
904 BView::SetFlags(flags);
905}
906
907
908void
909BTabView::SetResizingMode(uint32 mode)
910{
911 BView::SetResizingMode(mode);
912}
913
914
915void
916BTabView::GetPreferredSize(float *width, float *height)
917{
918 BView::GetPreferredSize(width, height);
919}
920
921
922void
923BTabView::ResizeToPreferred()
924{
925 BView::ResizeToPreferred();
926}
927
928
929BHandler *
930BTabView::ResolveSpecifier(BMessage *message, int32 index,
931 BMessage *specifier, int32 what, const char *property)
932{
933 BPropertyInfo propInfo(sPropertyList);
934
935 if (propInfo.FindMatch(message, 0, specifier, what, property) >= B_OK)
936 return this;
937
938 return BView::ResolveSpecifier(message, index, specifier, what,
939 property);
940}
941
942
943status_t
944BTabView::GetSupportedSuites(BMessage *message)
945{
946 message->AddString("suites", "suite/vnd.Be-tab-view");
947
948 BPropertyInfo propInfo(sPropertyList);
949 message->AddFlat("messages", &propInfo);
950
951 return BView::GetSupportedSuites(message);
952}
953
954
955void
956BTabView::AddTab(BView *target, BTab *tab)
957{
958 if (tab == NULL)
959 tab = new BTab(target);
960 else
961 tab->SetView(target);
962
963 fTabList->AddItem(tab);
964}
965
966
967BTab *
968BTabView::RemoveTab(int32 index)
969{
970 if (index < 0 || index >= CountTabs())
971 return NULL;
972
973 BTab *tab = (BTab *)fTabList->RemoveItem(index);
974 if (tab == NULL)
975 return NULL;
976
977 tab->Deselect();
978
979 if (index <= fSelection && fSelection != 0)
980 fSelection--;
981
982 if (CountTabs() == 0)
983 fFocus = -1;
984 else
985 Select(fSelection);
986
987 if (fFocus == CountTabs() - 1 || CountTabs() == 0)
988 SetFocusTab(fFocus, false);
989 else
990 SetFocusTab(fFocus, true);
991
992 return tab;
993}
994
995
996BTab *
997BTabView::TabAt(int32 index) const
998{
999 return (BTab *)fTabList->ItemAt(index);
1000}
1001
1002
1003void
1004BTabView::SetTabWidth(button_width width)
1005{
1006 fTabWidthSetting = width;
1007
1008 Invalidate();
1009}
1010
1011
1012button_width
1013BTabView::TabWidth() const
1014{
1015 return fTabWidthSetting;
1016}
1017
1018
1019void
1020BTabView::SetTabHeight(float height)
1021{
1022 if (fTabHeight == height)
1023 return;
1024
1025 fContainerView->MoveBy(0.0f, height - fTabHeight);
1026 fContainerView->ResizeBy(0.0f, height - fTabHeight);
1027
1028 fTabHeight = height;
1029
1030 Invalidate();
1031}
1032
1033
1034float
1035BTabView::TabHeight() const
1036{
1037 return fTabHeight;
1038}
1039
1040
1041BView *
1042BTabView::ContainerView() const
1043{
1044 return fContainerView;
1045}
1046
1047
1048int32
1049BTabView::CountTabs() const
1050{
1051 return fTabList->CountItems();
1052}
1053
1054
1055BView *
1056BTabView::ViewForTab(int32 tabIndex) const
1057{
1058 BTab *tab = TabAt(tabIndex);
1059 if (tab)
1060 return tab->View();
1061
1062 return NULL;
1063}
1064
1065
1066void
1067BTabView::SetSelectionMessage(BMessage* message)
1068{
1069 BInvoker::SetMessage(message);
1070}
1071
1072
1073BMessage*
1074BTabView::SelectionMessage() const
1075{
1076 return BInvoker::Message();
1077}
1078
1079
1080uint32
1081BTabView::SelectionCommand() const
1082{
1083 return BInvoker::Command();
1084}
1085
1086
1087void
1088BTabView::SelectionChanged()
1089{
1090 // Hook method to be implemented by subclasses
1091}
1092
1093
1094void
1095BTabView::_InitObject()
1096{
1097 fTabList = new BList;
1098
1099 fTabWidthSetting = B_WIDTH_AS_USUAL;
1100 fSelection = 0;
1101 fFocus = -1;
1102 fTabOffset = 0.0f;
1103
1104 rgb_color color = ui_color(B_PANEL_BACKGROUND_COLOR);
1105
1106 SetViewColor(color);
1107 SetLowColor(color);
1108
1109 font_height fh;
1110 GetFontHeight(&fh);
1111 fTabHeight = fh.ascent + fh.descent + fh.leading + 8.0f;
1112
1113 BRect bounds = Bounds();
1114
1115 bounds.top += TabHeight();
1116 bounds.InsetBy(3.0f, 3.0f);
1117
1118 fContainerView = new BView(bounds, "view container", B_FOLLOW_ALL,
1119 B_WILL_DRAW);
1120
1121 fContainerView->SetViewColor(color);
1122 fContainerView->SetLowColor(color);
1123
1124 AddChild(fContainerView);
1125}
1126
1127
1128void BTabView::_ReservedTabView3() {}
1129void BTabView::_ReservedTabView4() {}
1130void BTabView::_ReservedTabView5() {}
1131void BTabView::_ReservedTabView6() {}
1132void BTabView::_ReservedTabView7() {}
1133void BTabView::_ReservedTabView8() {}
1134void BTabView::_ReservedTabView9() {}
1135void BTabView::_ReservedTabView10() {}
1136void BTabView::_ReservedTabView11() {}
1137void BTabView::_ReservedTabView12() {}
1138
1139
1140BTabView::BTabView(const BTabView &tabView)
1141 : BView(tabView)
1142{
1143 // this is private and not functional, but exported
1144}
1145
1146
1147BTabView &BTabView::operator=(const BTabView &)
1148{
1149 // this is private and not functional, but exported
1150 return *this;
1151}