Ticket #2198: TabView.cpp.Invoker

File TabView.cpp.Invoker, 21.1 KB (added by shinta, 11 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}