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 20 static 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 33 BTab::BTab(BView *tabView) 34 : 35 fEnabled(true), 36 fSelected(false), 37 fFocus(false), 38 fView(tabView) 39 { 40 } 41 42 43 BTab::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 58 BTab::~BTab() 59 { 60 if (!fView) 61 return; 62 63 if (fSelected) 64 fView->RemoveSelf(); 65 66 delete fView; 67 } 68 69 70 BArchivable * 71 BTab::Instantiate(BMessage *archive) 72 { 73 if (validate_instantiation(archive, "BTab")) 74 return new BTab(archive); 75 76 return NULL; 77 } 78 79 80 status_t 81 BTab::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 94 status_t 95 BTab::Perform(uint32 d, void *arg) 96 { 97 return BArchivable::Perform(d, arg); 98 } 99 100 101 const char * 102 BTab::Label() const 103 { 104 if (fView) 105 return fView->Name(); 106 else 107 return NULL; 108 } 109 110 111 void 112 BTab::SetLabel(const char *label) 113 { 114 if (!label || !fView) 115 return; 116 117 fView->SetName(label); 118 } 119 120 121 bool 122 BTab::IsSelected() const 123 { 124 return fSelected; 125 } 126 127 128 void 129 BTab::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 141 void 142 BTab::Deselect() 143 { 144 if (View()) 145 View()->RemoveSelf(); 146 147 fSelected = false; 148 } 149 150 151 void 152 BTab::SetEnabled(bool enabled) 153 { 154 fEnabled = enabled; 155 } 156 157 158 bool 159 BTab::IsEnabled() const 160 { 161 return fEnabled; 162 } 163 164 165 void 166 BTab::MakeFocus(bool inFocus) 167 { 168 fFocus = inFocus; 169 } 170 171 172 bool 173 BTab::IsFocus() const 174 { 175 return fFocus; 176 } 177 178 179 void 180 BTab::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 193 BView * 194 BTab::View() const 195 { 196 return fView; 197 } 198 199 200 void 201 BTab::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 215 void 216 BTab::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 244 void 245 BTab::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 310 void BTab::_ReservedTab1() {} 311 void BTab::_ReservedTab2() {} 312 void BTab::_ReservedTab3() {} 313 void BTab::_ReservedTab4() {} 314 void BTab::_ReservedTab5() {} 315 void BTab::_ReservedTab6() {} 316 void BTab::_ReservedTab7() {} 317 void BTab::_ReservedTab8() {} 318 void BTab::_ReservedTab9() {} 319 void BTab::_ReservedTab10() {} 320 void BTab::_ReservedTab11() {} 321 void BTab::_ReservedTab12() {} 322 323 BTab &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 333 BTabView::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 345 BTabView::~BTabView() 346 { 347 for (int32 i = 0; i < CountTabs(); i++) { 348 delete TabAt(i); 349 } 350 351 delete fTabList; 352 } 353 354 355 BTabView::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 406 BArchivable * 407 BTabView::Instantiate(BMessage *archive) 408 { 409 if ( validate_instantiation(archive, "BTabView")) 410 return new BTabView(archive); 411 412 return NULL; 413 } 414 415 416 status_t 417 BTabView::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 461 status_t 462 BTabView::Perform(perform_code d, void *arg) 463 { 464 return BView::Perform(d, arg); 465 } 466 467 468 void 469 BTabView::WindowActivated(bool active) 470 { 471 BView::WindowActivated(active); 472 473 if (IsFocus()) 474 Invalidate(); 475 } 476 477 478 void 479 BTabView::AttachedToWindow() 480 { 481 BView::AttachedToWindow(); 482 483 Select(fSelection); 484 } 485 486 487 void 488 BTabView::AllAttached() 489 { 490 BView::AllAttached(); 491 } 492 493 494 void 495 BTabView::AllDetached() 496 { 497 BView::AllDetached(); 498 } 499 500 501 void 502 BTabView::DetachedFromWindow() 503 { 504 BView::DetachedFromWindow(); 505 } 506 507 508 void 509 BTabView::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 576 void 577 BTabView::FrameMoved(BPoint newLocation) 578 { 579 BView::FrameMoved(newLocation); 580 } 581 582 583 void 584 BTabView::FrameResized(float width,float height) 585 { 586 BView::FrameResized(width, height); 587 } 588 589 590 void 591 BTabView::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 626 void 627 BTabView::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 644 void 645 BTabView::MouseUp(BPoint point) 646 { 647 BView::MouseUp(point); 648 } 649 650 651 void 652 BTabView::MouseMoved(BPoint point, uint32 transit, const BMessage *message) 653 { 654 BView::MouseMoved(point, transit, message); 655 } 656 657 658 void 659 BTabView::Pulse() 660 { 661 BView::Pulse(); 662 } 663 664 665 void 666 BTabView::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 } 682 683 Invalidate(); 684 685 if(index != 0 && !Bounds().Contains(TabFrame(index))){ 686 if(!Bounds().Contains(TabFrame(index).LeftTop())) 687 fTabOffset += TabFrame(index).left - Bounds().left - 20.0f; 688 else 689 fTabOffset += TabFrame(index).right - Bounds().right + 20.0f; 690 691 Invalidate(); 692 } 693 694 /*MakeFocus(); 695 SetFocusTab(index, true); 696 FocusTab();*/ 697 } 698 699 700 int32 701 BTabView::Selection() const 702 { 703 return fSelection; 704 } 705 706 707 void 708 BTabView::MakeFocus(bool focused) 709 { 710 BView::MakeFocus(focused); 711 712 SetFocusTab(Selection(), focused); 713 } 714 715 716 void 717 BTabView::SetFocusTab(int32 tab, bool focused) 718 { 719 if (tab >= CountTabs()) 720 tab = 0; 721 722 if(tab < 0) 723 tab = CountTabs() - 1; 724 725 if (focused) { 726 if (tab == fFocus) 727 return; 728 729 if (fFocus != -1){ 730 if(TabAt (fFocus) != NULL) 731 TabAt(fFocus)->MakeFocus(false); 732 Invalidate(TabFrame(fFocus)); 733 } 734 if(TabAt(tab) != NULL){ 735 TabAt(tab)->MakeFocus(true); 736 Invalidate(TabFrame(tab)); 737 fFocus = tab; 738 } 739 } else if (fFocus != -1) { 740 TabAt(fFocus)->MakeFocus(false); 741 Invalidate(TabFrame(fFocus)); 742 fFocus = -1; 743 } 744 } 745 746 747 int32 748 BTabView::FocusTab() const 749 { 750 return fFocus; 751 } 752 753 754 void 755 BTabView::Draw(BRect updateRect) 756 { 757 DrawBox(DrawTabs()); 758 759 if (IsFocus() && fFocus != -1) 760 TabAt(fFocus)->DrawFocusMark(this, TabFrame(fFocus)); 761 } 762 763 764 BRect 765 BTabView::DrawTabs() 766 { 767 for (int32 i = 0; i < CountTabs(); i++) { 768 TabAt(i)->DrawTab(this, TabFrame(i), 769 i == fSelection ? B_TAB_FRONT : (i == 0) ? B_TAB_FIRST : B_TAB_ANY, 770 i + 1 != fSelection); 771 } 772 773 if (fSelection < CountTabs()) 774 return TabFrame(fSelection); 775 776 return BRect(); 777 } 778 779 780 void 781 BTabView::DrawBox(BRect selTabRect) 782 { 783 BRect rect = Bounds(); 784 BRect lastTabRect = TabFrame(CountTabs() - 1); 785 786 rgb_color noTint = ui_color(B_PANEL_BACKGROUND_COLOR); 787 rgb_color lightenMax = tint_color(noTint, B_LIGHTEN_MAX_TINT); 788 rgb_color darken1 = tint_color(noTint, B_DARKEN_1_TINT); 789 rgb_color darken2 = tint_color(noTint, B_DARKEN_2_TINT); 790 rgb_color darken4 = tint_color(noTint, B_DARKEN_4_TINT); 791 792 BeginLineArray(12); 793 794 int32 offset = (int32)ceilf(selTabRect.Height() / 2.0); 795 796 // outer lines 797 AddLine(BPoint(rect.left, rect.bottom - 1), 798 BPoint(rect.left, selTabRect.bottom), darken2); 799 if (selTabRect.left >= rect.left + 1) 800 AddLine(BPoint(rect.left + 1, selTabRect.bottom), 801 BPoint(selTabRect.left, selTabRect.bottom), darken2); 802 if (lastTabRect.right + offset + 1 <= rect.right - 1) 803 AddLine(BPoint(lastTabRect.right + offset + 1, selTabRect.bottom), 804 BPoint(rect.right - 1, selTabRect.bottom), darken2); 805 AddLine(BPoint(rect.right, selTabRect.bottom + 2), 806 BPoint(rect.right, rect.bottom), darken2); 807 AddLine(BPoint(rect.right - 1, rect.bottom), 808 BPoint(rect.left + 2, rect.bottom), darken2); 809 810 // inner lines 811 rect.InsetBy(1, 1); 812 selTabRect.bottom += 1; 813 814 AddLine(BPoint(rect.left, rect.bottom - 2), 815 BPoint(rect.left, selTabRect.bottom), lightenMax); 816 if (selTabRect.left >= rect.left + 1) 817 AddLine(BPoint(rect.left + 1, selTabRect.bottom), 818 BPoint(selTabRect.left, selTabRect.bottom), lightenMax); 819 if (selTabRect.right + offset + 1 <= rect.right - 2) 820 AddLine(BPoint(selTabRect.right + offset + 1, selTabRect.bottom), 821 BPoint(rect.right - 2, selTabRect.bottom), lightenMax); 822 AddLine(BPoint(rect.right, selTabRect.bottom), 823 BPoint(rect.right, rect.bottom), darken4); 824 AddLine(BPoint(rect.right - 1, rect.bottom), 825 BPoint(rect.left, rect.bottom), darken4); 826 827 // soft inner bevel at right/bottom 828 rect.right--; 829 rect.bottom--; 830 831 AddLine(BPoint(rect.right, selTabRect.bottom + 1), 832 BPoint(rect.right, rect.bottom), darken1); 833 AddLine(BPoint(rect.right - 1, rect.bottom), 834 BPoint(rect.left + 1, rect.bottom), darken1); 835 836 EndLineArray(); 837 } 838 839 #define X_OFFSET 0.0f 840 841 BRect 842 BTabView::TabFrame(int32 tab_index) const 843 { 844 // TODO: fix to remove "offset" in DrawTab and DrawLabel ... 845 switch (fTabWidthSetting) { 846 case B_WIDTH_FROM_LABEL: 847 { 848 float x = 6.0f; 849 for (int32 i = 0; i < tab_index; i++){ 850 x += StringWidth(TabAt(i)->Label()) + 20.0f; 851 } 852 853 return BRect(x - fTabOffset, 0.0f, 854 x - fTabOffset + StringWidth(TabAt(tab_index)->Label()) + 20.0f , fTabHeight); 855 856 857 /*float x = X_OFFSET; 858 for (int32 i = 0; i < tab_index; i++) 859 x += StringWidth(TabAt(i)->Label()) + 20.0f; 860 861 return BRect(x, 0.0f, 862 x + StringWidth(TabAt(tab_index)->Label()) + 20.0f, fTabHeight);*/ 863 } 864 865 case B_WIDTH_FROM_WIDEST: 866 { 867 float width = 0.0f; 868 869 for (int32 i = 0; i < CountTabs(); i++) { 870 float tabWidth = StringWidth(TabAt(i)->Label()) + 20.0f; 871 if (tabWidth > width) 872 width = tabWidth; 873 } 874 return BRect((6.0f + tab_index * width) - fTabOffset, 0.0f, 875 (6.0f + tab_index * width + width) - fTabOffset, fTabHeight); 876 /*float width = 0.0f; 877 878 for (int32 i = 0; i < CountTabs(); i++) { 879 float tabWidth = StringWidth(TabAt(i)->Label()) + 20.0f; 880 881 if (tabWidth > width) 882 width = tabWidth; 883 } 884 885 return BRect(X_OFFSET + tab_index * width, 0.0f, 886 X_OFFSET + tab_index * width + width, fTabHeight);*/ 887 } 888 889 case B_WIDTH_AS_USUAL: 890 default: 891 return BRect((6.0f + tab_index * 100.0f) - fTabOffset, 0.0f, 892 (6.0f + tab_index * 100.0f + 100.0f) - fTabOffset, fTabHeight); 893 /*return BRect(X_OFFSET + tab_index * 100.0f, 0.0f, 894 X_OFFSET + tab_index * 100.0f + 100.0f, fTabHeight);*/ 895 } 896 } 897 898 899 void 900 BTabView::SetFlags(uint32 flags) 901 { 902 BView::SetFlags(flags); 903 } 904 905 906 void 907 BTabView::SetResizingMode(uint32 mode) 908 { 909 BView::SetResizingMode(mode); 910 } 911 912 913 void 914 BTabView::GetPreferredSize(float *width, float *height) 915 { 916 BView::GetPreferredSize(width, height); 917 } 918 919 920 void 921 BTabView::ResizeToPreferred() 922 { 923 BView::ResizeToPreferred(); 924 } 925 926 927 BHandler * 928 BTabView::ResolveSpecifier(BMessage *message, int32 index, 929 BMessage *specifier, int32 what, const char *property) 930 { 931 BPropertyInfo propInfo(sPropertyList); 932 933 if (propInfo.FindMatch(message, 0, specifier, what, property) >= B_OK) 934 return this; 935 936 return BView::ResolveSpecifier(message, index, specifier, what, 937 property); 938 } 939 940 941 status_t 942 BTabView::GetSupportedSuites(BMessage *message) 943 { 944 message->AddString("suites", "suite/vnd.Be-tab-view"); 945 946 BPropertyInfo propInfo(sPropertyList); 947 message->AddFlat("messages", &propInfo); 948 949 return BView::GetSupportedSuites(message); 950 } 951 952 953 void 954 BTabView::AddTab(BView *target, BTab *tab) 955 { 956 if (tab == NULL) 957 tab = new BTab(target); 958 else 959 tab->SetView(target); 960 961 fTabList->AddItem(tab); 962 } 963 964 965 BTab * 966 BTabView::RemoveTab(int32 index) 967 { 968 if (index < 0 || index >= CountTabs()) 969 return NULL; 970 971 BTab *tab = (BTab *)fTabList->RemoveItem(index); 972 if (tab == NULL) 973 return NULL; 974 975 tab->Deselect(); 976 977 if (index <= fSelection && fSelection != 0) 978 fSelection--; 979 980 if(CountTabs() == 0) 981 fFocus = -1; 982 else 983 Select(fSelection); 984 985 if (fFocus == CountTabs() - 1 || CountTabs() == 0) 986 SetFocusTab(fFocus, false); 987 else 988 SetFocusTab(fFocus, true); 989 990 return tab; 991 } 992 993 994 BTab * 995 BTabView::TabAt(int32 index) const 996 { 997 return (BTab *)fTabList->ItemAt(index); 998 } 999 1000 1001 void 1002 BTabView::SetTabWidth(button_width width) 1003 { 1004 fTabWidthSetting = width; 1005 1006 Invalidate(); 1007 } 1008 1009 1010 button_width 1011 BTabView::TabWidth() const 1012 { 1013 return fTabWidthSetting; 1014 } 1015 1016 1017 void 1018 BTabView::SetTabHeight(float height) 1019 { 1020 if (fTabHeight == height) 1021 return; 1022 1023 fContainerView->MoveBy(0.0f, height - fTabHeight); 1024 fContainerView->ResizeBy(0.0f, height - fTabHeight); 1025 1026 fTabHeight = height; 1027 1028 Invalidate(); 1029 } 1030 1031 1032 float 1033 BTabView::TabHeight() const 1034 { 1035 return fTabHeight; 1036 } 1037 1038 1039 BView * 1040 BTabView::ContainerView() const 1041 { 1042 return fContainerView; 1043 } 1044 1045 1046 int32 1047 BTabView::CountTabs() const 1048 { 1049 return fTabList->CountItems(); 1050 } 1051 1052 1053 BView * 1054 BTabView::ViewForTab(int32 tabIndex) const 1055 { 1056 BTab *tab = TabAt(tabIndex); 1057 if (tab) 1058 return tab->View(); 1059 1060 return NULL; 1061 } 1062 1063 1064 void 1065 BTabView::_InitObject() 1066 { 1067 fTabList = new BList; 1068 1069 fTabWidthSetting = B_WIDTH_AS_USUAL; 1070 fSelection = 0; 1071 fFocus = -1; 1072 fTabOffset = 0.0f; 1073 1074 rgb_color color = ui_color(B_PANEL_BACKGROUND_COLOR); 1075 1076 SetViewColor(color); 1077 SetLowColor(color); 1078 1079 font_height fh; 1080 GetFontHeight(&fh); 1081 fTabHeight = fh.ascent + fh.descent + fh.leading + 8.0f; 1082 1083 BRect bounds = Bounds(); 1084 1085 bounds.top += TabHeight(); 1086 bounds.InsetBy(3.0f, 3.0f); 1087 1088 fContainerView = new BView(bounds, "view container", B_FOLLOW_ALL, 1089 B_WILL_DRAW); 1090 1091 fContainerView->SetViewColor(color); 1092 fContainerView->SetLowColor(color); 1093 1094 AddChild(fContainerView); 1095 } 1096 1097 1098 void BTabView::_ReservedTabView1() {} 1099 void BTabView::_ReservedTabView2() {} 1100 void BTabView::_ReservedTabView3() {} 1101 void BTabView::_ReservedTabView4() {} 1102 void BTabView::_ReservedTabView5() {} 1103 void BTabView::_ReservedTabView6() {} 1104 void BTabView::_ReservedTabView7() {} 1105 void BTabView::_ReservedTabView8() {} 1106 void BTabView::_ReservedTabView9() {} 1107 void BTabView::_ReservedTabView10() {} 1108 void BTabView::_ReservedTabView11() {} 1109 void BTabView::_ReservedTabView12() {} 1110 1111 1112 BTabView::BTabView(const BTabView &tabView) 1113 : BView(tabView) 1114 { 1115 // this is private and not functional, but exported 1116 } 1117 1118 1119 BTabView &BTabView::operator=(const BTabView &) 1120 { 1121 // this is private and not functional, but exported 1122 return *this; 1123 } 1124