Ticket #13673: 0003-BTabView-implement-drawing-tabs-on-different-borders.patch

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

    From c600991f9bc034abeccb6e1da0315a5debc7892a 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 different borders.
    
    ---
     headers/os/interface/TabView.h |  16 +-
     src/kits/interface/TabView.cpp | 336 ++++++++++++++++++++++++++++++++++-------
     2 files changed, 292 insertions(+), 60 deletions(-)
    
    diff --git a/headers/os/interface/TabView.h b/headers/os/interface/TabView.h
    index 1547610d38..2e8d05367c 100644
    a b enum tab_position {  
    1919};
    2020
    2121
     22enum tab_side {
     23    B_LEFT_BORDER       = 1 << 0,
     24    B_RIGHT_BORDER      = 1 << 1,
     25    B_TOP_BORDER        = 1 << 2,
     26    B_BOTTOM_BORDER     = 1 << 3
     27};
     28
     29
    2230class BTab : public BArchivable {
    2331public:
    2432                                BTab(BView* contentsView = NULL);
    public:  
    165173    virtual void                SetBorder(border_style borderStyle);
    166174            border_style        Border() const;
    167175
     176    virtual void                SetTabSide(tab_side tabSide);
     177            tab_side            TabSide() const;
     178
    168179            BView*              ContainerView() const;
    169180
    170181            int32               CountTabs() const;
    public:  
    172183
    173184private:
    174185    // FBC padding and forbidden methods
    175     virtual void                _ReservedTabView2();
    176     virtual void                _ReservedTabView3();
    177186    virtual void                _ReservedTabView4();
    178187    virtual void                _ReservedTabView5();
    179188    virtual void                _ReservedTabView6();
    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..c9451eae86 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 B_TOP_BORDER:
     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 B_BOTTOM_BORDER:
     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 B_LEFT_BORDER:
     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 B_RIGHT_BORDER:
     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 B_TOP_BORDER:
     283        case B_BOTTOM_BORDER:
     284            rotation = 0.0f;
     285            break;
     286        case B_LEFT_BORDER:
     287            rotation = 270.0f;
     288            break;
     289        case B_RIGHT_BORDER:
     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() == B_TOP_BORDER
     323        || fTabView->TabSide() == B_BOTTOM_BORDER) {
     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() == B_LEFT_BORDER
     332        || fTabView->TabSide() == B_RIGHT_BORDER) {
     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 B_TOP_BORDER:
     345                frame.bottom -= 1.0f;
     346                break;
     347            case B_BOTTOM_BORDER:
     348                frame.top += 1.0f;
     349                break;
     350            case B_LEFT_BORDER:
     351                frame.right -= 1.0f;
     352                break;
     353            case B_RIGHT_BORDER:
     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
     364
    285365    DrawLabel(owner, frame);
    286366}
    287367
    BTabView::BTabView(BMessage* archive)  
    365445    if (archive->FindInt32("_border_style", (int32*)&fBorderStyle) != B_OK)
    366446        fBorderStyle = B_FANCY_BORDER;
    367447
     448    if (archive->FindInt32("_tab_side", (int32*)&fTabSide) != B_OK)
     449        fTabSide = B_TOP_BORDER;
     450
    368451    int32 i = 0;
    369452    BMessage tabMsg;
    370453
    BTabView::Archive(BMessage* archive, bool deep) const  
    426509        result = archive->AddInt32("_sel", fSelection);
    427510    if (result == B_OK && fBorderStyle != B_FANCY_BORDER)
    428511        result = archive->AddInt32("_border_style", fBorderStyle);
     512    if (result == B_OK && fTabSide != B_TOP_BORDER)
     513        result = archive->AddInt32("_tab_side", fTabSide);
    429514
    430515    if (result == B_OK && deep) {
    431516        for (int32 i = 0; i < CountTabs(); i++) {
    BTabView::KeyDown(const char* bytes, int32 numBytes)  
    642727void
    643728BTabView::MouseDown(BPoint where)
    644729{
    645     if (where.y > fTabHeight)
    646         return;
    647 
    648730    for (int32 i = 0; i < CountTabs(); i++) {
    649731        if (TabFrame(i).Contains(where)
    650732            && i != Selection()) {
    BTabView::Draw(BRect updateRect)  
    800882BRect
    801883BTabView::DrawTabs()
    802884{
    803     // draw an inactive tab frame behind all tabs
    804885    BRect bounds(Bounds());
    805     bounds.bottom = fTabHeight;
     886    BRect tabsBounds;
     887    uint32 borders;
    806888    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;
     889    if (fTabSide == B_TOP_BORDER || fTabSide == B_BOTTOM_BORDER) {
     890        if (fTabSide == B_TOP_BORDER)
     891            bounds.bottom = fTabHeight;
     892        else
     893            bounds.top = bounds.bottom - fTabHeight;
     894        tabsBounds = bounds;
     895            // make a copy for later
     896
     897        // draw an inactive tab frame behind all tabs
     898        borders = BControlLook::B_TOP_BORDER | BControlLook::B_BOTTOM_BORDER;
     899        if (fBorderStyle == B_NO_BORDER) {
     900            // removes left border that is an artifact of DrawInactiveTab()
     901            bounds.left -= 1;
     902        } else {
     903            borders |= BControlLook::B_LEFT_BORDER
     904                | BControlLook::B_RIGHT_BORDER;
     905        }
     906
     907        // DrawInactiveTab draws 2px border
     908        // draw a little wider tab frame to align B_PLAIN_BORDER with it
     909        if (fBorderStyle == B_PLAIN_BORDER) {
     910            bounds.left -= 1;
     911            bounds.right += 1;
     912        }
     913    } else if(fTabSide == B_LEFT_BORDER || fTabSide == B_RIGHT_BORDER) {
     914        if (fTabSide == B_LEFT_BORDER)
     915            bounds.right = fTabHeight;
     916        else
     917            bounds.left = bounds.right - fTabHeight;
     918        tabsBounds = bounds;
     919            // make a copy for later
     920
     921        // draw an inactive tab frame behind all tabs
     922        borders = BControlLook::B_LEFT_BORDER | BControlLook::B_RIGHT_BORDER;
     923        if (fBorderStyle == B_NO_BORDER) {
     924            // removes top border that is an artifact of DrawInactiveTab()
     925            bounds.top -= 1;
     926        } else {
     927            borders |= BControlLook::B_TOP_BORDER
     928                | BControlLook::B_BOTTOM_BORDER;
     929        }
    813930
    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;
     931        // DrawInactiveTab draws 2px border
     932        // draw a little wider tab frame to align B_PLAIN_BORDER with it
     933        if (fBorderStyle == B_PLAIN_BORDER) {
     934            bounds.top -= 1;
     935            bounds.bottom += 1;
     936        }
    819937    }
    820938
    821     be_control_look->DrawInactiveTab(this, bounds, bounds, base, 0, borders);
     939    be_control_look->DrawInactiveTab(this, bounds, bounds, base, 0,
     940        borders, fTabSide);
    822941
    823942    // draw the tabs on top of the inactive tab bounds
    824     float right = 0.0f;
    825943    BRect activeTabFrame;
    826944    int32 tabCount = CountTabs();
    827945    for (int32 i = 0; i < tabCount; i++) {
    BTabView::DrawTabs()  
    830948            activeTabFrame = tabFrame;
    831949
    832950        TabAt(i)->DrawTab(this, tabFrame,
    833             i == fSelection ? B_TAB_FRONT : (i == 0) ? B_TAB_FIRST : B_TAB_ANY,
     951            i == fSelection ? B_TAB_FRONT :
     952                (i == 0) ? B_TAB_FIRST : B_TAB_ANY,
    834953            i + 1 != fSelection);
    835         right = tabFrame.right;
    836954    }
    837955
    838     if (right < bounds.right) {
     956    float last = 0.0f;
     957    float lastTab = 0.0f;
     958    if (fTabSide == B_TOP_BORDER || fTabSide == B_BOTTOM_BORDER) {
     959        lastTab = TabFrame(tabCount - 1).right;
     960        last = bounds.right;
     961        tabsBounds.left = tabsBounds.right = lastTab;
     962        borders = BControlLook::B_TOP_BORDER | BControlLook::B_BOTTOM_BORDER;
     963    } else if (fTabSide == B_LEFT_BORDER || fTabSide == B_RIGHT_BORDER) {
     964        lastTab = TabFrame(tabCount - 1).bottom;
     965        last = bounds.bottom;
     966        tabsBounds.top = tabsBounds.bottom = lastTab;
     967        borders = BControlLook::B_LEFT_BORDER | BControlLook::B_RIGHT_BORDER;
     968    }
     969
     970    if (lastTab < last) {
    839971        // 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);
     972        be_control_look->DrawInactiveTab(this, tabsBounds, tabsBounds, base, 0,
     973            borders, fTabSide);
    846974    }
    847975
    848976    return fSelection < CountTabs() ? TabFrame(fSelection) : BRect();
    void  
    853981BTabView::DrawBox(BRect selectedTabRect)
    854982{
    855983    BRect rect(Bounds());
    856     rect.top = fTabHeight;
     984    uint32 bordersToDraw = BControlLook::B_ALL_BORDERS;
     985    switch (fTabSide) {
     986        case B_TOP_BORDER:
     987            bordersToDraw &= ~BControlLook::B_TOP_BORDER;
     988            rect.top = fTabHeight;
     989            break;
     990        case B_BOTTOM_BORDER:
     991            bordersToDraw &= ~BControlLook::B_BOTTOM_BORDER;
     992            rect.bottom -= fTabHeight;
     993            break;
     994        case B_LEFT_BORDER:
     995            bordersToDraw &= ~BControlLook::B_LEFT_BORDER;
     996            rect.left = fTabHeight;
     997            break;
     998        case B_RIGHT_BORDER:
     999            bordersToDraw &= ~BControlLook::B_RIGHT_BORDER;
     1000            rect.right -= fTabHeight;
     1001            break;
     1002    }
    8571003
    8581004    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) {
     1005    if (fBorderStyle == B_FANCY_BORDER)
     1006        be_control_look->DrawGroupFrame(this, rect, rect, base, bordersToDraw);
     1007    else if (fBorderStyle == B_PLAIN_BORDER) {
    8631008        be_control_look->DrawBorder(this, rect, rect, base, B_PLAIN_BORDER,
    864             0, BControlLook::B_ALL_BORDERS & ~BControlLook::B_TOP_BORDER);
     1009            0, bordersToDraw);
    8651010    } else
    8661011        ; // B_NO_BORDER draws no box
    8671012}
    BTabView::TabFrame(int32 index) const  
    8761021    float width = 100.0f;
    8771022    float height = fTabHeight;
    8781023    float offset = BControlLook::ComposeSpacing(B_USE_WINDOW_SPACING);
     1024    BRect bounds(Bounds());
    8791025
    8801026    switch (fTabWidthSetting) {
    8811027        case B_WIDTH_FROM_LABEL:
    BTabView::TabFrame(int32 index) const  
    8851031                x += StringWidth(TabAt(i)->Label()) + 20.0f;
    8861032            }
    8871033
    888             return BRect(offset + x, 0.0f,
    889                 offset + x + StringWidth(TabAt(index)->Label()) + 20.0f,
    890                 height);
     1034            switch (fTabSide) {
     1035                case B_TOP_BORDER:
     1036                    return BRect(offset + x, 0.0f,
     1037                        offset + x + StringWidth(TabAt(index)->Label()) + 20.0f,
     1038                        height);
     1039                case B_BOTTOM_BORDER:
     1040                    return BRect(offset + x, bounds.bottom - height,
     1041                        offset + x + StringWidth(TabAt(index)->Label()) + 20.0f,
     1042                        bounds.bottom);
     1043                case B_LEFT_BORDER:
     1044                    return BRect(0.0f, offset + x, height, offset + x
     1045                        + StringWidth(TabAt(index)->Label()) + 20.0f);
     1046                case B_RIGHT_BORDER:
     1047                    return BRect(bounds.right - height, offset + x,
     1048                        bounds.right, offset + x
     1049                            + StringWidth(TabAt(index)->Label()) + 20.0f);
     1050                default:
     1051                    return BRect();
     1052            }
    8911053        }
    8921054
    8931055        case B_WIDTH_FROM_WIDEST:
    BTabView::TabFrame(int32 index) const  
    9011063
    9021064        case B_WIDTH_AS_USUAL:
    9031065        default:
    904             return BRect(offset + index * width, 0.0f,
    905                 offset + index * width + width, height);
     1066            switch (fTabSide) {
     1067                case B_TOP_BORDER:
     1068                    return BRect(offset + index * width, 0.0f,
     1069                        offset + index * width + width, height);
     1070                case B_BOTTOM_BORDER:
     1071                    return BRect(offset + index * width, bounds.bottom - height,
     1072                        offset + index * width + width, bounds.bottom);
     1073                case B_LEFT_BORDER:
     1074                    return BRect(0.0f, offset + index * width, height,
     1075                        offset + index * width + width);
     1076                case B_RIGHT_BORDER:
     1077                    return BRect(bounds.right - height, offset + index * width,
     1078                        bounds.right, offset + index * width + width);
     1079                default:
     1080                    return BRect();
     1081            }
    9061082    }
    9071083}
    9081084
    BTabView::Border() const  
    11531329}
    11541330
    11551331
     1332void
     1333BTabView::SetTabSide(tab_side tabSide)
     1334{
     1335    if (fTabSide == tabSide)
     1336        return;
     1337
     1338    fTabSide = tabSide;
     1339    _LayoutContainerView(Flags() & B_SUPPORTS_LAYOUT);
     1340}
     1341
     1342
     1343tab_side
     1344BTabView::TabSide() const
     1345{
     1346    return fTabSide;
     1347}
     1348
     1349
    11561350BView*
    11571351BTabView::ContainerView() const
    11581352{
    BTabView::_InitObject(bool layouted, button_width width)  
    11881382    fFocus = -1;
    11891383    fTabOffset = 0.0f;
    11901384    fBorderStyle = B_FANCY_BORDER;
     1385    fTabSide = B_TOP_BORDER;
    11911386
    11921387    SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
    11931388    SetLowUIColor(B_PANEL_BACKGROUND_COLOR);
    BTabView::_LayoutContainerView(bool layouted)  
    12921487        }
    12931488        BGroupLayout* layout = dynamic_cast<BGroupLayout*>(GetLayout());
    12941489        if (layout != NULL) {
    1295             layout->SetInsets(borderWidth, borderWidth + TabHeight()
    1296                 - topBorderOffset, borderWidth, borderWidth);
     1490            float inset = borderWidth + TabHeight() - topBorderOffset;
     1491            switch (fTabSide) {
     1492                case B_TOP_BORDER:
     1493                    layout->SetInsets(borderWidth, inset, borderWidth,
     1494                        borderWidth);
     1495                    break;
     1496                case B_BOTTOM_BORDER:
     1497                    layout->SetInsets(borderWidth, borderWidth, borderWidth,
     1498                        inset);
     1499                    break;
     1500                case B_LEFT_BORDER:
     1501                    layout->SetInsets(inset, borderWidth, borderWidth,
     1502                        borderWidth);
     1503                    break;
     1504                case B_RIGHT_BORDER:
     1505                    layout->SetInsets(borderWidth, borderWidth, inset,
     1506                        borderWidth);
     1507                    break;
     1508            }
    12971509        }
    12981510    } else {
    12991511        BRect bounds = Bounds();
    1300 
    1301         bounds.top += TabHeight();
     1512        switch (fTabSide) {
     1513            case B_TOP_BORDER:
     1514                bounds.top += TabHeight();
     1515                break;
     1516            case B_BOTTOM_BORDER:
     1517                bounds.bottom -= TabHeight();
     1518                break;
     1519            case B_LEFT_BORDER:
     1520                bounds.left += TabHeight();
     1521                break;
     1522            case B_RIGHT_BORDER:
     1523                bounds.right -= TabHeight();
     1524                break;
     1525        }
    13021526        bounds.InsetBy(borderWidth, borderWidth);
    13031527
    13041528        fContainerView->MoveTo(bounds.left, bounds.top);
    BTabView::_LayoutContainerView(bool layouted)  
    13101534// #pragma mark - FBC and forbidden
    13111535
    13121536
    1313 void BTabView::_ReservedTabView2() {}
    1314 void BTabView::_ReservedTabView3() {}
    13151537void BTabView::_ReservedTabView4() {}
    13161538void BTabView::_ReservedTabView5() {}
    13171539void BTabView::_ReservedTabView6() {}