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 , 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: 86 86 87 87 class BTabView : public BView { 88 88 public: 89 enum tab_side { 90 kLeftSide = 1 << 0, 91 kRightSide = 1 << 1, 92 kTopSide = 1 << 2, 93 kBottomSide = 1 << 3 94 }; 95 89 96 BTabView(const char* name, 90 97 button_width width = B_WIDTH_AS_USUAL, 91 98 uint32 flags = B_FULL_UPDATE_ON_RESIZE … … public: 165 172 virtual void SetBorder(border_style borderStyle); 166 173 border_style Border() const; 167 174 175 virtual void SetTabSide(tab_side tabSide); 176 tab_side TabSide() const; 177 168 178 BView* ContainerView() const; 169 179 170 180 int32 CountTabs() const; … … public: 172 182 173 183 private: 174 184 // FBC padding and forbidden methods 175 virtual void _ReservedTabView2();176 185 virtual void _ReservedTabView3(); 177 186 virtual void _ReservedTabView4(); 178 187 virtual void _ReservedTabView5(); … … private: 205 214 int32 fFocus; 206 215 float fTabOffset; 207 216 border_style fBorderStyle; 217 tab_side fTabSide; 208 218 209 uint32 _reserved[ 10];219 uint32 _reserved[9]; 210 220 }; 211 221 212 222 #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) 243 243 owner->SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); 244 244 245 245 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 } 250 272 } 251 273 252 274 253 275 void 254 276 BTab::DrawLabel(BView* owner, BRect frame) 255 277 { 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); 256 309 be_control_look->DrawLabel(owner, Label(), frame, frame, 257 310 ui_color(B_PANEL_BACKGROUND_COLOR), 258 311 IsEnabled() ? 0 : BPrivate::BControlLook::B_DISABLED, 259 312 BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER)); 313 owner->SetTransform(BAffineTransform()); 260 314 } 261 315 262 316 … … void 264 318 BTab::DrawTab(BView* owner, BRect frame, tab_position position, bool full) 265 319 { 266 320 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; 269 325 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; 272 328 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 } 275 341 276 342 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 } 278 357 be_control_look->DrawActiveTab(owner, frame, frame, no_tint, 0, 279 borders );358 borders, fTabView->TabSide()); 280 359 } else { 281 360 be_control_look->DrawInactiveTab(owner, frame, frame, no_tint, 0, 282 borders );361 borders, fTabView->TabSide()); 283 362 } 284 363 285 364 DrawLabel(owner, frame); … … BTabView::BTabView(BMessage* archive) 365 444 if (archive->FindInt32("_border_style", (int32*)&fBorderStyle) != B_OK) 366 445 fBorderStyle = B_FANCY_BORDER; 367 446 447 if (archive->FindInt32("_TabSide", (int32*)&fTabSide) != B_OK) 448 fTabSide = kTopSide; 449 368 450 int32 i = 0; 369 451 BMessage tabMsg; 370 452 … … BTabView::Archive(BMessage* archive, bool deep) const 426 508 result = archive->AddInt32("_sel", fSelection); 427 509 if (result == B_OK && fBorderStyle != B_FANCY_BORDER) 428 510 result = archive->AddInt32("_border_style", fBorderStyle); 511 if (result == B_OK && fTabSide != kTopSide) 512 result = archive->AddInt32("_TabSide", fTabSide); 429 513 430 514 if (result == B_OK && deep) { 431 515 for (int32 i = 0; i < CountTabs(); i++) { … … BTabView::KeyDown(const char* bytes, int32 numBytes) 642 726 void 643 727 BTabView::MouseDown(BPoint where) 644 728 { 645 if (where.y > fTabHeight)646 return;647 648 729 for (int32 i = 0; i < CountTabs(); i++) { 649 730 if (TabFrame(i).Contains(where) 650 731 && i != Selection()) { … … BTabView::Draw(BRect updateRect) 800 881 BRect 801 882 BTabView::DrawTabs() 802 883 { 803 // draw an inactive tab frame behind all tabs804 884 BRect bounds(Bounds()); 805 bounds.bottom = fTabHeight; 885 BRect tabsBounds; 886 uint32 borders; 806 887 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 } 813 929 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 } 819 936 } 820 937 821 be_control_look->DrawInactiveTab(this, bounds, bounds, base, 0, borders); 938 be_control_look->DrawInactiveTab(this, bounds, bounds, base, 0, 939 borders, fTabSide); 822 940 823 941 // draw the tabs on top of the inactive tab bounds 824 float right = 0.0f;825 942 BRect activeTabFrame; 826 943 int32 tabCount = CountTabs(); 827 944 for (int32 i = 0; i < tabCount; i++) { … … BTabView::DrawTabs() 830 947 activeTabFrame = tabFrame; 831 948 832 949 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, 834 952 i + 1 != fSelection); 835 right = tabFrame.right;836 953 } 837 954 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) { 839 970 // 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); 846 973 } 847 974 848 975 return fSelection < CountTabs() ? TabFrame(fSelection) : BRect(); … … void 853 980 BTabView::DrawBox(BRect selectedTabRect) 854 981 { 855 982 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 } 857 1002 858 1003 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) { 863 1007 be_control_look->DrawBorder(this, rect, rect, base, B_PLAIN_BORDER, 864 0, BControlLook::B_ALL_BORDERS & ~BControlLook::B_TOP_BORDER);1008 0, bordersToDraw); 865 1009 } else 866 1010 ; // B_NO_BORDER draws no box 867 1011 } … … BTabView::TabFrame(int32 index) const 876 1020 float width = 100.0f; 877 1021 float height = fTabHeight; 878 1022 float offset = BControlLook::ComposeSpacing(B_USE_WINDOW_SPACING); 1023 BRect bounds(Bounds()); 879 1024 880 1025 switch (fTabWidthSetting) { 881 1026 case B_WIDTH_FROM_LABEL: … … BTabView::TabFrame(int32 index) const 885 1030 x += StringWidth(TabAt(i)->Label()) + 20.0f; 886 1031 } 887 1032 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 } 891 1052 } 892 1053 893 1054 case B_WIDTH_FROM_WIDEST: … … BTabView::TabFrame(int32 index) const 901 1062 902 1063 case B_WIDTH_AS_USUAL: 903 1064 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 } 906 1081 } 907 1082 } 908 1083 … … BTabView::Border() const 1153 1328 } 1154 1329 1155 1330 1331 void 1332 BTabView::SetTabSide(tab_side tabSide) 1333 { 1334 if (fTabSide == tabSide) 1335 return; 1336 1337 fTabSide = tabSide; 1338 _LayoutContainerView(Flags() & B_SUPPORTS_LAYOUT); 1339 } 1340 1341 1342 BTabView::tab_side 1343 BTabView::TabSide() const 1344 { 1345 return fTabSide; 1346 } 1347 1348 1156 1349 BView* 1157 1350 BTabView::ContainerView() const 1158 1351 { … … BTabView::_InitObject(bool layouted, button_width width) 1188 1381 fFocus = -1; 1189 1382 fTabOffset = 0.0f; 1190 1383 fBorderStyle = B_FANCY_BORDER; 1384 fTabSide = kTopSide; 1191 1385 1192 1386 SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 1193 1387 SetLowUIColor(B_PANEL_BACKGROUND_COLOR); … … BTabView::_LayoutContainerView(bool layouted) 1292 1486 } 1293 1487 BGroupLayout* layout = dynamic_cast<BGroupLayout*>(GetLayout()); 1294 1488 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 } 1297 1508 } 1298 1509 } else { 1299 1510 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 } 1302 1525 bounds.InsetBy(borderWidth, borderWidth); 1303 1526 1304 1527 fContainerView->MoveTo(bounds.left, bounds.top); … … BTabView::_LayoutContainerView(bool layouted) 1310 1533 // #pragma mark - FBC and forbidden 1311 1534 1312 1535 1313 void BTabView::_ReservedTabView2() {}1314 1536 void BTabView::_ReservedTabView3() {} 1315 1537 void BTabView::_ReservedTabView4() {} 1316 1538 void BTabView::_ReservedTabView5() {}