Ticket #13673: 0003-BTabView-implement-drawing-tabs-on-all-sides.patch

File 0003-BTabView-implement-drawing-tabs-on-all-sides.patch, 16.4 KB (added by KapiX, 7 years ago)
  • headers/os/interface/TabView.h

    From 33b284b7cd13e4d53cc4ad136205c0cfb5ee9d58 Mon Sep 17 00:00:00 2001
    From: Kacper Kasper <kacperkasper@gmail.com>
    Date: Sat, 19 Aug 2017 19:32:31 +0200
    Subject: [PATCH 3/3] BTabView: implement drawing tabs on all sides.
    
    ---
     headers/os/interface/TabView.h |  14 +-
     src/kits/interface/TabView.cpp | 334 ++++++++++++++++++++++++++++++++++-------
     2 files changed, 290 insertions(+), 58 deletions(-)
    
    diff --git a/headers/os/interface/TabView.h b/headers/os/interface/TabView.h
    index 1547610d38..03b485ecc5 100644
    a b private:  
    8686
    8787class BTabView : public BView {
    8888public:
     89            enum tab_side {
     90                kLeftSide   = 1 << 0,
     91                kRightSide  = 1 << 1,
     92                kTopSide    = 1 << 2,
     93                kBottomSide = 1 << 3
     94            };
     95
    8996                                BTabView(const char* name,
    9097                                    button_width width = B_WIDTH_AS_USUAL,
    9198                                    uint32 flags = B_FULL_UPDATE_ON_RESIZE
    public:  
    165172    virtual void                SetBorder(border_style borderStyle);
    166173            border_style        Border() const;
    167174
     175    virtual void                SetTabSide(tab_side tabSide);
     176            tab_side            TabSide() const;
     177
    168178            BView*              ContainerView() const;
    169179
    170180            int32               CountTabs() const;
    public:  
    172182
    173183private:
    174184    // FBC padding and forbidden methods
    175     virtual void                _ReservedTabView2();
    176185    virtual void                _ReservedTabView3();
    177186    virtual void                _ReservedTabView4();
    178187    virtual void                _ReservedTabView5();
    private:  
    205214            int32               fFocus;
    206215            float               fTabOffset;
    207216            border_style        fBorderStyle;
     217            tab_side            fTabSide;
    208218
    209             uint32              _reserved[10];
     219            uint32              _reserved[9];
    210220};
    211221
    212222#endif // _TAB_VIEW_H
  • src/kits/interface/TabView.cpp

    diff --git a/src/kits/interface/TabView.cpp b/src/kits/interface/TabView.cpp
    index 1d589b1dd9..ddc4823f78 100644
    a b BTab::DrawFocusMark(BView* owner, BRect frame)  
    243243    owner->SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
    244244
    245245    float offset = IsSelected() ? 3 : 2;
    246     owner->StrokeLine(BPoint((frame.left + frame.right - width) / 2.0,
    247             frame.bottom - offset),
    248         BPoint((frame.left + frame.right + width) / 2.0,
    249             frame.bottom - offset));
     246    switch (fTabView->TabSide()) {
     247        case BTabView::kTopSide:
     248            owner->StrokeLine(BPoint((frame.left + frame.right - width) / 2.0,
     249                    frame.bottom - offset),
     250                BPoint((frame.left + frame.right + width) / 2.0,
     251                    frame.bottom - offset));
     252            break;
     253        case BTabView::kBottomSide:
     254            owner->StrokeLine(BPoint((frame.left + frame.right - width) / 2.0,
     255                    frame.top + offset),
     256                BPoint((frame.left + frame.right + width) / 2.0,
     257                    frame.top + offset));
     258            break;
     259        case BTabView::kLeftSide:
     260            owner->StrokeLine(BPoint(frame.right - offset,
     261                    (frame.top + frame.bottom - width) / 2.0),
     262                BPoint(frame.right - offset,
     263                    (frame.top + frame.bottom + width) / 2.0));
     264            break;
     265        case BTabView::kRightSide:
     266            owner->StrokeLine(BPoint(frame.left + offset,
     267                    (frame.top + frame.bottom - width) / 2.0),
     268                BPoint(frame.left + offset,
     269                    (frame.top + frame.bottom + width) / 2.0));
     270            break;
     271    }
    250272}
    251273
    252274
    253275void
    254276BTab::DrawLabel(BView* owner, BRect frame)
    255277{
     278    float rotation;
     279    BPoint center(frame.left + frame.Width() / 2,
     280        frame.top + frame.Height() / 2);
     281    switch (fTabView->TabSide()) {
     282        case BTabView::kTopSide:
     283        case BTabView::kBottomSide:
     284            rotation = 0.0f;
     285            break;
     286        case BTabView::kLeftSide:
     287            rotation = 270.0f;
     288            break;
     289        case BTabView::kRightSide:
     290            rotation = 90.0f;
     291            break;
     292    }
     293
     294    if (rotation != 0.0f) {
     295        // DrawLabel doesn't allow rendering rotated text
     296        // rotate frame first and BAffineTransform will handle the rotation
     297        // we can't give "unrotated" frame because it comes from
     298        // BTabView::TabFrame and it is also used to handle mouse clicks
     299        BRect originalFrame(frame);
     300        frame.top = center.y - originalFrame.Width() / 2;
     301        frame.bottom = center.y + originalFrame.Width() / 2;
     302        frame.left = center.x - originalFrame.Height() / 2;
     303        frame.right = center.x + originalFrame.Height() / 2;
     304    }
     305
     306    BAffineTransform transform;
     307    transform.RotateBy(center, rotation * M_PI / 180.0f);
     308    owner->SetTransform(transform);
    256309    be_control_look->DrawLabel(owner, Label(), frame, frame,
    257310        ui_color(B_PANEL_BACKGROUND_COLOR),
    258311        IsEnabled() ? 0 : BPrivate::BControlLook::B_DISABLED,
    259312        BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER));
     313    owner->SetTransform(BAffineTransform());
    260314}
    261315
    262316
    void  
    264318BTab::DrawTab(BView* owner, BRect frame, tab_position position, bool full)
    265319{
    266320    rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR);
    267     uint32 borders = BControlLook::B_TOP_BORDER
    268         | BControlLook::B_BOTTOM_BORDER;
     321    uint32 borders;
     322    if (fTabView->TabSide() == BTabView::kTopSide
     323        || fTabView->TabSide() == BTabView::kBottomSide) {
     324        borders = BControlLook::B_TOP_BORDER | BControlLook::B_BOTTOM_BORDER;
    269325
    270     if (frame.left == owner->Bounds().left)
    271         borders |= BControlLook::B_LEFT_BORDER;
     326        if (frame.left == owner->Bounds().left)
     327            borders |= BControlLook::B_LEFT_BORDER;
    272328
    273     if (frame.right == owner->Bounds().right)
    274         borders |= BControlLook::B_RIGHT_BORDER;
     329        if (frame.right == owner->Bounds().right)
     330            borders |= BControlLook::B_RIGHT_BORDER;
     331    } else if (fTabView->TabSide() == BTabView::kLeftSide
     332        || fTabView->TabSide() == BTabView::kRightSide) {
     333        borders = BControlLook::B_LEFT_BORDER | BControlLook::B_RIGHT_BORDER;
     334
     335        if (frame.top == owner->Bounds().top)
     336            borders |= BControlLook::B_TOP_BORDER;
     337
     338        if (frame.bottom == owner->Bounds().bottom)
     339            borders |= BControlLook::B_BOTTOM_BORDER;
     340    }
    275341
    276342    if (position == B_TAB_FRONT) {
    277         frame.bottom -= 1.0f;
     343        switch (fTabView->TabSide()) {
     344            case BTabView::kTopSide:
     345                frame.bottom -= 1.0f;
     346                break;
     347            case BTabView::kBottomSide:
     348                frame.top += 1.0f;
     349                break;
     350            case BTabView::kLeftSide:
     351                frame.right -= 1.0f;
     352                break;
     353            case BTabView::kRightSide:
     354                frame.left += 1.0f;
     355                break;
     356        }
    278357        be_control_look->DrawActiveTab(owner, frame, frame, no_tint, 0,
    279             borders);
     358            borders, fTabView->TabSide());
    280359    } else {
    281360        be_control_look->DrawInactiveTab(owner, frame, frame, no_tint, 0,
    282             borders);
     361            borders, fTabView->TabSide());
    283362    }
    284363
    285364    DrawLabel(owner, frame);
    BTabView::BTabView(BMessage* archive)  
    365444    if (archive->FindInt32("_border_style", (int32*)&fBorderStyle) != B_OK)
    366445        fBorderStyle = B_FANCY_BORDER;
    367446
     447    if (archive->FindInt32("_TabSide", (int32*)&fTabSide) != B_OK)
     448        fTabSide = kTopSide;
     449
    368450    int32 i = 0;
    369451    BMessage tabMsg;
    370452
    BTabView::Archive(BMessage* archive, bool deep) const  
    426508        result = archive->AddInt32("_sel", fSelection);
    427509    if (result == B_OK && fBorderStyle != B_FANCY_BORDER)
    428510        result = archive->AddInt32("_border_style", fBorderStyle);
     511    if (result == B_OK && fTabSide != kTopSide)
     512        result = archive->AddInt32("_TabSide", fTabSide);
    429513
    430514    if (result == B_OK && deep) {
    431515        for (int32 i = 0; i < CountTabs(); i++) {
    BTabView::KeyDown(const char* bytes, int32 numBytes)  
    642726void
    643727BTabView::MouseDown(BPoint where)
    644728{
    645     if (where.y > fTabHeight)
    646         return;
    647 
    648729    for (int32 i = 0; i < CountTabs(); i++) {
    649730        if (TabFrame(i).Contains(where)
    650731            && i != Selection()) {
    BTabView::Draw(BRect updateRect)  
    800881BRect
    801882BTabView::DrawTabs()
    802883{
    803     // draw an inactive tab frame behind all tabs
    804884    BRect bounds(Bounds());
    805     bounds.bottom = fTabHeight;
     885    BRect tabsBounds;
     886    uint32 borders;
    806887    rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
    807     uint32 borders = BControlLook::B_TOP_BORDER | BControlLook::B_BOTTOM_BORDER;
    808     if (fBorderStyle == B_NO_BORDER) {
    809         // removes left border that is an artifact of DrawInactiveTab()
    810         bounds.left -= 1;
    811     } else
    812         borders |= BControlLook::B_LEFT_BORDER | BControlLook::B_RIGHT_BORDER;
     888    if (fTabSide == kTopSide || fTabSide == kBottomSide) {
     889        if (fTabSide == kTopSide)
     890            bounds.bottom = fTabHeight;
     891        else
     892            bounds.top = bounds.bottom - fTabHeight;
     893        tabsBounds = bounds;
     894            // make a copy for later
     895
     896        // draw an inactive tab frame behind all tabs
     897        borders = BControlLook::B_TOP_BORDER | BControlLook::B_BOTTOM_BORDER;
     898        if (fBorderStyle == B_NO_BORDER) {
     899            // removes left border that is an artifact of DrawInactiveTab()
     900            bounds.left -= 1;
     901        } else {
     902            borders |= BControlLook::B_LEFT_BORDER
     903                | BControlLook::B_RIGHT_BORDER;
     904        }
     905
     906        // DrawInactiveTab draws 2px border
     907        // draw a little wider tab frame to align B_PLAIN_BORDER with it
     908        if (fBorderStyle == B_PLAIN_BORDER) {
     909            bounds.left -= 1;
     910            bounds.right += 1;
     911        }
     912    } else if (fTabSide == kLeftSide || fTabSide == kRightSide) {
     913        if (fTabSide == kLeftSide)
     914            bounds.right = fTabHeight;
     915        else
     916            bounds.left = bounds.right - fTabHeight;
     917        tabsBounds = bounds;
     918            // make a copy for later
     919
     920        // draw an inactive tab frame behind all tabs
     921        borders = BControlLook::B_LEFT_BORDER | BControlLook::B_RIGHT_BORDER;
     922        if (fBorderStyle == B_NO_BORDER) {
     923            // removes top border that is an artifact of DrawInactiveTab()
     924            bounds.top -= 1;
     925        } else {
     926            borders |= BControlLook::B_TOP_BORDER
     927                | BControlLook::B_BOTTOM_BORDER;
     928        }
    813929
    814     // DrawInactiveTab draws 2px border
    815     // draw a little wider tab frame to align B_PLAIN_BORDER with it
    816     if (fBorderStyle == B_PLAIN_BORDER) {
    817         bounds.left -= 1;
    818         bounds.right += 1;
     930        // DrawInactiveTab draws 2px border
     931        // draw a little wider tab frame to align B_PLAIN_BORDER with it
     932        if (fBorderStyle == B_PLAIN_BORDER) {
     933            bounds.top -= 1;
     934            bounds.bottom += 1;
     935        }
    819936    }
    820937
    821     be_control_look->DrawInactiveTab(this, bounds, bounds, base, 0, borders);
     938    be_control_look->DrawInactiveTab(this, bounds, bounds, base, 0,
     939        borders, fTabSide);
    822940
    823941    // draw the tabs on top of the inactive tab bounds
    824     float right = 0.0f;
    825942    BRect activeTabFrame;
    826943    int32 tabCount = CountTabs();
    827944    for (int32 i = 0; i < tabCount; i++) {
    BTabView::DrawTabs()  
    830947            activeTabFrame = tabFrame;
    831948
    832949        TabAt(i)->DrawTab(this, tabFrame,
    833             i == fSelection ? B_TAB_FRONT : (i == 0) ? B_TAB_FIRST : B_TAB_ANY,
     950            i == fSelection ? B_TAB_FRONT :
     951                (i == 0) ? B_TAB_FIRST : B_TAB_ANY,
    834952            i + 1 != fSelection);
    835         right = tabFrame.right;
    836953    }
    837954
    838     if (right < bounds.right) {
     955    float last = 0.0f;
     956    float lastTab = 0.0f;
     957    if (fTabSide == kTopSide || fTabSide == kBottomSide) {
     958        lastTab = TabFrame(tabCount - 1).right;
     959        last = bounds.right;
     960        tabsBounds.left = tabsBounds.right = lastTab;
     961        borders = BControlLook::B_TOP_BORDER | BControlLook::B_BOTTOM_BORDER;
     962    } else if (fTabSide == kLeftSide || fTabSide == kRightSide) {
     963        lastTab = TabFrame(tabCount - 1).bottom;
     964        last = bounds.bottom;
     965        tabsBounds.top = tabsBounds.bottom = lastTab;
     966        borders = BControlLook::B_LEFT_BORDER | BControlLook::B_RIGHT_BORDER;
     967    }
     968
     969    if (lastTab < last) {
    839970        // draw a 1px right border on the last tab
    840         bounds = Bounds();
    841         bounds.left = bounds.right = right;
    842         bounds.bottom = fTabHeight;
    843         borders = BControlLook::B_TOP_BORDER;
    844         be_control_look->DrawInactiveTab(this, bounds, bounds, base, 0,
    845             BControlLook::B_TOP_BORDER | BControlLook::B_BOTTOM_BORDER);
     971        be_control_look->DrawInactiveTab(this, tabsBounds, tabsBounds, base, 0,
     972            borders, fTabSide);
    846973    }
    847974
    848975    return fSelection < CountTabs() ? TabFrame(fSelection) : BRect();
    void  
    853980BTabView::DrawBox(BRect selectedTabRect)
    854981{
    855982    BRect rect(Bounds());
    856     rect.top = fTabHeight;
     983    uint32 bordersToDraw = BControlLook::B_ALL_BORDERS;
     984    switch (fTabSide) {
     985        case kTopSide:
     986            bordersToDraw &= ~BControlLook::B_TOP_BORDER;
     987            rect.top = fTabHeight;
     988            break;
     989        case kBottomSide:
     990            bordersToDraw &= ~BControlLook::B_BOTTOM_BORDER;
     991            rect.bottom -= fTabHeight;
     992            break;
     993        case kLeftSide:
     994            bordersToDraw &= ~BControlLook::B_LEFT_BORDER;
     995            rect.left = fTabHeight;
     996            break;
     997        case kRightSide:
     998            bordersToDraw &= ~BControlLook::B_RIGHT_BORDER;
     999            rect.right -= fTabHeight;
     1000            break;
     1001    }
    8571002
    8581003    rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
    859     if (fBorderStyle == B_FANCY_BORDER) {
    860         be_control_look->DrawGroupFrame(this, rect, rect, base,
    861             BControlLook::B_ALL_BORDERS & ~BControlLook::B_TOP_BORDER);
    862     } else if (fBorderStyle == B_PLAIN_BORDER) {
     1004    if (fBorderStyle == B_FANCY_BORDER)
     1005        be_control_look->DrawGroupFrame(this, rect, rect, base, bordersToDraw);
     1006    else if (fBorderStyle == B_PLAIN_BORDER) {
    8631007        be_control_look->DrawBorder(this, rect, rect, base, B_PLAIN_BORDER,
    864             0, BControlLook::B_ALL_BORDERS & ~BControlLook::B_TOP_BORDER);
     1008            0, bordersToDraw);
    8651009    } else
    8661010        ; // B_NO_BORDER draws no box
    8671011}
    BTabView::TabFrame(int32 index) const  
    8761020    float width = 100.0f;
    8771021    float height = fTabHeight;
    8781022    float offset = BControlLook::ComposeSpacing(B_USE_WINDOW_SPACING);
     1023    BRect bounds(Bounds());
    8791024
    8801025    switch (fTabWidthSetting) {
    8811026        case B_WIDTH_FROM_LABEL:
    BTabView::TabFrame(int32 index) const  
    8851030                x += StringWidth(TabAt(i)->Label()) + 20.0f;
    8861031            }
    8871032
    888             return BRect(offset + x, 0.0f,
    889                 offset + x + StringWidth(TabAt(index)->Label()) + 20.0f,
    890                 height);
     1033            switch (fTabSide) {
     1034                case kTopSide:
     1035                    return BRect(offset + x, 0.0f,
     1036                        offset + x + StringWidth(TabAt(index)->Label()) + 20.0f,
     1037                        height);
     1038                case kBottomSide:
     1039                    return BRect(offset + x, bounds.bottom - height,
     1040                        offset + x + StringWidth(TabAt(index)->Label()) + 20.0f,
     1041                        bounds.bottom);
     1042                case kLeftSide:
     1043                    return BRect(0.0f, offset + x, height, offset + x
     1044                        + StringWidth(TabAt(index)->Label()) + 20.0f);
     1045                case kRightSide:
     1046                    return BRect(bounds.right - height, offset + x,
     1047                        bounds.right, offset + x
     1048                            + StringWidth(TabAt(index)->Label()) + 20.0f);
     1049                default:
     1050                    return BRect();
     1051            }
    8911052        }
    8921053
    8931054        case B_WIDTH_FROM_WIDEST:
    BTabView::TabFrame(int32 index) const  
    9011062
    9021063        case B_WIDTH_AS_USUAL:
    9031064        default:
    904             return BRect(offset + index * width, 0.0f,
    905                 offset + index * width + width, height);
     1065            switch (fTabSide) {
     1066                case kTopSide:
     1067                    return BRect(offset + index * width, 0.0f,
     1068                        offset + index * width + width, height);
     1069                case kBottomSide:
     1070                    return BRect(offset + index * width, bounds.bottom - height,
     1071                        offset + index * width + width, bounds.bottom);
     1072                case kLeftSide:
     1073                    return BRect(0.0f, offset + index * width, height,
     1074                        offset + index * width + width);
     1075                case kRightSide:
     1076                    return BRect(bounds.right - height, offset + index * width,
     1077                        bounds.right, offset + index * width + width);
     1078                default:
     1079                    return BRect();
     1080            }
    9061081    }
    9071082}
    9081083
    BTabView::Border() const  
    11531328}
    11541329
    11551330
     1331void
     1332BTabView::SetTabSide(tab_side tabSide)
     1333{
     1334    if (fTabSide == tabSide)
     1335        return;
     1336
     1337    fTabSide = tabSide;
     1338    _LayoutContainerView(Flags() & B_SUPPORTS_LAYOUT);
     1339}
     1340
     1341
     1342BTabView::tab_side
     1343BTabView::TabSide() const
     1344{
     1345    return fTabSide;
     1346}
     1347
     1348
    11561349BView*
    11571350BTabView::ContainerView() const
    11581351{
    BTabView::_InitObject(bool layouted, button_width width)  
    11881381    fFocus = -1;
    11891382    fTabOffset = 0.0f;
    11901383    fBorderStyle = B_FANCY_BORDER;
     1384    fTabSide = kTopSide;
    11911385
    11921386    SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
    11931387    SetLowUIColor(B_PANEL_BACKGROUND_COLOR);
    BTabView::_LayoutContainerView(bool layouted)  
    12921486        }
    12931487        BGroupLayout* layout = dynamic_cast<BGroupLayout*>(GetLayout());
    12941488        if (layout != NULL) {
    1295             layout->SetInsets(borderWidth, borderWidth + TabHeight()
    1296                 - topBorderOffset, borderWidth, borderWidth);
     1489            float inset = borderWidth + TabHeight() - topBorderOffset;
     1490            switch (fTabSide) {
     1491                case kTopSide:
     1492                    layout->SetInsets(borderWidth, inset, borderWidth,
     1493                        borderWidth);
     1494                    break;
     1495                case kBottomSide:
     1496                    layout->SetInsets(borderWidth, borderWidth, borderWidth,
     1497                        inset);
     1498                    break;
     1499                case kLeftSide:
     1500                    layout->SetInsets(inset, borderWidth, borderWidth,
     1501                        borderWidth);
     1502                    break;
     1503                case kRightSide:
     1504                    layout->SetInsets(borderWidth, borderWidth, inset,
     1505                        borderWidth);
     1506                    break;
     1507            }
    12971508        }
    12981509    } else {
    12991510        BRect bounds = Bounds();
    1300 
    1301         bounds.top += TabHeight();
     1511        switch (fTabSide) {
     1512            case kTopSide:
     1513                bounds.top += TabHeight();
     1514                break;
     1515            case kBottomSide:
     1516                bounds.bottom -= TabHeight();
     1517                break;
     1518            case kLeftSide:
     1519                bounds.left += TabHeight();
     1520                break;
     1521            case kRightSide:
     1522                bounds.right -= TabHeight();
     1523                break;
     1524        }
    13021525        bounds.InsetBy(borderWidth, borderWidth);
    13031526
    13041527        fContainerView->MoveTo(bounds.left, bounds.top);
    BTabView::_LayoutContainerView(bool layouted)  
    13101533// #pragma mark - FBC and forbidden
    13111534
    13121535
    1313 void BTabView::_ReservedTabView2() {}
    13141536void BTabView::_ReservedTabView3() {}
    13151537void BTabView::_ReservedTabView4() {}
    13161538void BTabView::_ReservedTabView5() {}