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 if (message->what == B_GET_PROPERTY || message->what == B_SET_PROPERTY) { 512 BMessage reply(B_REPLY); 513 bool handled = false; 514 515 BMessage specifier; 516 int32 index; 517 int32 form; 518 const char *property; 519 if (message->GetCurrentSpecifier(&index, &specifier, &form, &property) == B_OK) { 520 if (strcmp(property, "Selection") == 0) { 521 if (message->what == B_GET_PROPERTY) { 522 reply.AddInt32("result", fSelection); 523 handled = true; 524 } else { 525 // B_GET_PROPERTY 526 int32 selection; 527 if (message->FindInt32("data", &selection) == B_OK) { 528 Select(selection); 529 reply.AddInt32("error", B_OK); 530 handled = true; 531 } 532 } 533 } 534 } 535 536 if (handled) { 537 message->SendReply(&reply); 538 return; 539 } 540 } 541 BView::MessageReceived(message); 542 } 543 544 545 void 546 BTabView::FrameMoved(BPoint newLocation) 547 { 548 BView::FrameMoved(newLocation); 549 } 550 551 552 void 553 BTabView::FrameResized(float width,float height) 554 { 555 BView::FrameResized(width, height); 556 } 557 558 559 void 560 BTabView::KeyDown(const char *bytes, int32 numBytes) 561 { 562 if (IsHidden()) 563 return; 564 565 switch (bytes[0]) { 566 case B_DOWN_ARROW: 567 case B_LEFT_ARROW: { 568 int32 focus = fFocus - 1; 569 if (focus < 0) 570 focus = CountTabs() - 1; 571 SetFocusTab(focus, true); 572 break; 573 } 574 575 case B_UP_ARROW: 576 case B_RIGHT_ARROW: { 577 int32 focus = fFocus + 1; 578 if (focus >= CountTabs()) 579 focus = 0; 580 SetFocusTab(focus, true); 581 break; 582 } 583 584 case B_RETURN: 585 case B_SPACE: 586 Select(FocusTab()); 587 break; 588 589 default: 590 BView::KeyDown(bytes, numBytes); 591 } 592 } 593 594 595 void 596 BTabView::MouseDown(BPoint point) 597 { 598 if (point.y > fTabHeight) 599 return; 600 601 for (int32 i = 0; i < CountTabs(); i++) { 602 if (TabFrame(i).Contains(point) 603 && i != Selection()) { 604 Select(i); 605 return; 606 } 607 } 608 609 BView::MouseDown(point); 610 } 611 612 613 void 614 BTabView::MouseUp(BPoint point) 615 { 616 BView::MouseUp(point); 617 } 618 619 620 void 621 BTabView::MouseMoved(BPoint point, uint32 transit, const BMessage *message) 622 { 623 BView::MouseMoved(point, transit, message); 624 } 625 626 627 void 628 BTabView::Pulse() 629 { 630 BView::Pulse(); 631 } 632 633 634 void 635 BTabView::Select(int32 index) 636 { 637 if (index < 0 || index >= CountTabs()) 638 index = Selection(); 639 640 BTab *tab = TabAt(Selection()); 641 if (tab) 642 tab->Deselect(); 643 644 tab = TabAt(index); 645 if (tab && ContainerView()) { 646 if(index == 0) 647 fTabOffset = 0.0f; 648 tab->Select(ContainerView()); 649 fSelection = index; 650 } 651 652 Invalidate(); 653 654 if(index != 0 && !Bounds().Contains(TabFrame(index))){ 655 if(!Bounds().Contains(TabFrame(index).LeftTop())) 656 fTabOffset += TabFrame(index).left - Bounds().left - 20.0f; 657 else 658 fTabOffset += TabFrame(index).right - Bounds().right + 20.0f; 659 660 Invalidate(); 661 } 662 663 /*MakeFocus(); 664 SetFocusTab(index, true); 665 FocusTab();*/ 666 } 667 668 669 int32 670 BTabView::Selection() const 671 { 672 return fSelection; 673 } 674 675 676 void 677 BTabView::MakeFocus(bool focused) 678 { 679 BView::MakeFocus(focused); 680 681 SetFocusTab(Selection(), focused); 682 } 683 684 685 void 686 BTabView::SetFocusTab(int32 tab, bool focused) 687 { 688 if (tab >= CountTabs()) 689 tab = 0; 690 691 if(tab < 0) 692 tab = CountTabs() - 1; 693 694 if (focused) { 695 if (tab == fFocus) 696 return; 697 698 if (fFocus != -1){ 699 if(TabAt (fFocus) != NULL) 700 TabAt(fFocus)->MakeFocus(false); 701 Invalidate(TabFrame(fFocus)); 702 } 703 if(TabAt(tab) != NULL){ 704 TabAt(tab)->MakeFocus(true); 705 Invalidate(TabFrame(tab)); 706 fFocus = tab; 707 } 708 } else if (fFocus != -1) { 709 TabAt(fFocus)->MakeFocus(false); 710 Invalidate(TabFrame(fFocus)); 711 fFocus = -1; 712 } 713 } 714 715 716 int32 717 BTabView::FocusTab() const 718 { 719 return fFocus; 720 } 721 722 723 void 724 BTabView::Draw(BRect updateRect) 725 { 726 DrawBox(DrawTabs()); 727 728 if (IsFocus() && fFocus != -1) 729 TabAt(fFocus)->DrawFocusMark(this, TabFrame(fFocus)); 730 } 731 732 733 BRect 734 BTabView::DrawTabs() 735 { 736 for (int32 i = 0; i < CountTabs(); i++) { 737 TabAt(i)->DrawTab(this, TabFrame(i), 738 i == fSelection ? B_TAB_FRONT : (i == 0) ? B_TAB_FIRST : B_TAB_ANY, 739 i + 1 != fSelection); 740 } 741 742 if (fSelection < CountTabs()) 743 return TabFrame(fSelection); 744 745 return BRect(); 746 } 747 748 749 void 750 BTabView::DrawBox(BRect selTabRect) 751 { 752 BRect rect = Bounds(); 753 BRect lastTabRect = TabFrame(CountTabs() - 1); 754 755 rgb_color noTint = ui_color(B_PANEL_BACKGROUND_COLOR); 756 rgb_color lightenMax = tint_color(noTint, B_LIGHTEN_MAX_TINT); 757 rgb_color darken1 = tint_color(noTint, B_DARKEN_1_TINT); 758 rgb_color darken2 = tint_color(noTint, B_DARKEN_2_TINT); 759 rgb_color darken4 = tint_color(noTint, B_DARKEN_4_TINT); 760 761 BeginLineArray(12); 762 763 int32 offset = (int32)ceilf(selTabRect.Height() / 2.0); 764 765 // outer lines 766 AddLine(BPoint(rect.left, rect.bottom - 1), 767 BPoint(rect.left, selTabRect.bottom), darken2); 768 if (selTabRect.left >= rect.left + 1) 769 AddLine(BPoint(rect.left + 1, selTabRect.bottom), 770 BPoint(selTabRect.left, selTabRect.bottom), darken2); 771 if (lastTabRect.right + offset + 1 <= rect.right - 1) 772 AddLine(BPoint(lastTabRect.right + offset + 1, selTabRect.bottom), 773 BPoint(rect.right - 1, selTabRect.bottom), darken2); 774 AddLine(BPoint(rect.right, selTabRect.bottom + 2), 775 BPoint(rect.right, rect.bottom), darken2); 776 AddLine(BPoint(rect.right - 1, rect.bottom), 777 BPoint(rect.left + 2, rect.bottom), darken2); 778 779 // inner lines 780 rect.InsetBy(1, 1); 781 selTabRect.bottom += 1; 782 783 AddLine(BPoint(rect.left, rect.bottom - 2), 784 BPoint(rect.left, selTabRect.bottom), lightenMax); 785 if (selTabRect.left >= rect.left + 1) 786 AddLine(BPoint(rect.left + 1, selTabRect.bottom), 787 BPoint(selTabRect.left, selTabRect.bottom), lightenMax); 788 if (selTabRect.right + offset + 1 <= rect.right - 2) 789 AddLine(BPoint(selTabRect.right + offset + 1, selTabRect.bottom), 790 BPoint(rect.right - 2, selTabRect.bottom), lightenMax); 791 AddLine(BPoint(rect.right, selTabRect.bottom), 792 BPoint(rect.right, rect.bottom), darken4); 793 AddLine(BPoint(rect.right - 1, rect.bottom), 794 BPoint(rect.left, rect.bottom), darken4); 795 796 // soft inner bevel at right/bottom 797 rect.right--; 798 rect.bottom--; 799 800 AddLine(BPoint(rect.right, selTabRect.bottom + 1), 801 BPoint(rect.right, rect.bottom), darken1); 802 AddLine(BPoint(rect.right - 1, rect.bottom), 803 BPoint(rect.left + 1, rect.bottom), darken1); 804 805 EndLineArray(); 806 } 807 808 #define X_OFFSET 0.0f 809 810 BRect 811 BTabView::TabFrame(int32 tab_index) const 812 { 813 // TODO: fix to remove "offset" in DrawTab and DrawLabel ... 814 switch (fTabWidthSetting) { 815 case B_WIDTH_FROM_LABEL: 816 { 817 float x = 6.0f; 818 for (int32 i = 0; i < tab_index; i++){ 819 x += StringWidth(TabAt(i)->Label()) + 20.0f; 820 } 821 822 return BRect(x - fTabOffset, 0.0f, 823 x - fTabOffset + StringWidth(TabAt(tab_index)->Label()) + 20.0f , fTabHeight); 824 825 826 /*float x = X_OFFSET; 827 for (int32 i = 0; i < tab_index; i++) 828 x += StringWidth(TabAt(i)->Label()) + 20.0f; 829 830 return BRect(x, 0.0f, 831 x + StringWidth(TabAt(tab_index)->Label()) + 20.0f, fTabHeight);*/ 832 } 833 834 case B_WIDTH_FROM_WIDEST: 835 { 836 float width = 0.0f; 837 838 for (int32 i = 0; i < CountTabs(); i++) { 839 float tabWidth = StringWidth(TabAt(i)->Label()) + 20.0f; 840 if (tabWidth > width) 841 width = tabWidth; 842 } 843 return BRect((6.0f + tab_index * width) - fTabOffset, 0.0f, 844 (6.0f + tab_index * width + width) - fTabOffset, fTabHeight); 845 /*float width = 0.0f; 846 847 for (int32 i = 0; i < CountTabs(); i++) { 848 float tabWidth = StringWidth(TabAt(i)->Label()) + 20.0f; 849 850 if (tabWidth > width) 851 width = tabWidth; 852 } 853 854 return BRect(X_OFFSET + tab_index * width, 0.0f, 855 X_OFFSET + tab_index * width + width, fTabHeight);*/ 856 } 857 858 case B_WIDTH_AS_USUAL: 859 default: 860 return BRect((6.0f + tab_index * 100.0f) - fTabOffset, 0.0f, 861 (6.0f + tab_index * 100.0f + 100.0f) - fTabOffset, fTabHeight); 862 /*return BRect(X_OFFSET + tab_index * 100.0f, 0.0f, 863 X_OFFSET + tab_index * 100.0f + 100.0f, fTabHeight);*/ 864 } 865 } 866 867 868 void 869 BTabView::SetFlags(uint32 flags) 870 { 871 BView::SetFlags(flags); 872 } 873 874 875 void 876 BTabView::SetResizingMode(uint32 mode) 877 { 878 BView::SetResizingMode(mode); 879 } 880 881 882 void 883 BTabView::GetPreferredSize(float *width, float *height) 884 { 885 BView::GetPreferredSize(width, height); 886 } 887 888 889 void 890 BTabView::ResizeToPreferred() 891 { 892 BView::ResizeToPreferred(); 893 } 894 895 896 BHandler * 897 BTabView::ResolveSpecifier(BMessage *message, int32 index, 898 BMessage *specifier, int32 what, const char *property) 899 { 900 BPropertyInfo propInfo(sPropertyList); 901 902 if (propInfo.FindMatch(message, 0, specifier, what, property) >= B_OK) 903 return this; 904 905 return BView::ResolveSpecifier(message, index, specifier, what, 906 property); 907 } 908 909 910 status_t 911 BTabView::GetSupportedSuites(BMessage *message) 912 { 913 message->AddString("suites", "suite/vnd.Be-tab-view"); 914 915 BPropertyInfo propInfo(sPropertyList); 916 message->AddFlat("messages", &propInfo); 917 918 return BView::GetSupportedSuites(message); 919 } 920 921 922 void 923 BTabView::AddTab(BView *target, BTab *tab) 924 { 925 if (tab == NULL) 926 tab = new BTab(target); 927 else 928 tab->SetView(target); 929 930 fTabList->AddItem(tab); 931 } 932 933 934 BTab * 935 BTabView::RemoveTab(int32 index) 936 { 937 if (index < 0 || index >= CountTabs()) 938 return NULL; 939 940 BTab *tab = (BTab *)fTabList->RemoveItem(index); 941 if (tab == NULL) 942 return NULL; 943 944 tab->Deselect(); 945 946 if (index <= fSelection && fSelection != 0) 947 fSelection--; 948 949 if(CountTabs() == 0) 950 fFocus = -1; 951 else 952 Select(fSelection); 953 954 if (fFocus == CountTabs() - 1 || CountTabs() == 0) 955 SetFocusTab(fFocus, false); 956 else 957 SetFocusTab(fFocus, true); 958 959 return tab; 960 } 961 962 963 BTab * 964 BTabView::TabAt(int32 index) const 965 { 966 return (BTab *)fTabList->ItemAt(index); 967 } 968 969 970 void 971 BTabView::SetTabWidth(button_width width) 972 { 973 fTabWidthSetting = width; 974 975 Invalidate(); 976 } 977 978 979 button_width 980 BTabView::TabWidth() const 981 { 982 return fTabWidthSetting; 983 } 984 985 986 void 987 BTabView::SetTabHeight(float height) 988 { 989 if (fTabHeight == height) 990 return; 991 992 fContainerView->MoveBy(0.0f, height - fTabHeight); 993 fContainerView->ResizeBy(0.0f, height - fTabHeight); 994 995 fTabHeight = height; 996 997 Invalidate(); 998 } 999 1000 1001 float 1002 BTabView::TabHeight() const 1003 { 1004 return fTabHeight; 1005 } 1006 1007 1008 BView * 1009 BTabView::ContainerView() const 1010 { 1011 return fContainerView; 1012 } 1013 1014 1015 int32 1016 BTabView::CountTabs() const 1017 { 1018 return fTabList->CountItems(); 1019 } 1020 1021 1022 BView * 1023 BTabView::ViewForTab(int32 tabIndex) const 1024 { 1025 BTab *tab = TabAt(tabIndex); 1026 if (tab) 1027 return tab->View(); 1028 1029 return NULL; 1030 } 1031 1032 1033 void 1034 BTabView::_InitObject() 1035 { 1036 fTabList = new BList; 1037 1038 fTabWidthSetting = B_WIDTH_AS_USUAL; 1039 fSelection = 0; 1040 fFocus = -1; 1041 fTabOffset = 0.0f; 1042 1043 rgb_color color = ui_color(B_PANEL_BACKGROUND_COLOR); 1044 1045 SetViewColor(color); 1046 SetLowColor(color); 1047 1048 font_height fh; 1049 GetFontHeight(&fh); 1050 fTabHeight = fh.ascent + fh.descent + fh.leading + 8.0f; 1051 1052 BRect bounds = Bounds(); 1053 1054 bounds.top += TabHeight(); 1055 bounds.InsetBy(3.0f, 3.0f); 1056 1057 fContainerView = new BView(bounds, "view container", B_FOLLOW_ALL, 1058 B_WILL_DRAW); 1059 1060 fContainerView->SetViewColor(color); 1061 fContainerView->SetLowColor(color); 1062 1063 AddChild(fContainerView); 1064 } 1065 1066 1067 void BTabView::_ReservedTabView1() {} 1068 void BTabView::_ReservedTabView2() {} 1069 void BTabView::_ReservedTabView3() {} 1070 void BTabView::_ReservedTabView4() {} 1071 void BTabView::_ReservedTabView5() {} 1072 void BTabView::_ReservedTabView6() {} 1073 void BTabView::_ReservedTabView7() {} 1074 void BTabView::_ReservedTabView8() {} 1075 void BTabView::_ReservedTabView9() {} 1076 void BTabView::_ReservedTabView10() {} 1077 void BTabView::_ReservedTabView11() {} 1078 void BTabView::_ReservedTabView12() {} 1079 1080 1081 BTabView::BTabView(const BTabView &tabView) 1082 : BView(tabView) 1083 { 1084 // this is private and not functional, but exported 1085 } 1086 1087 1088 BTabView &BTabView::operator=(const BTabView &) 1089 { 1090 // this is private and not functional, but exported 1091 return *this; 1092 } 1093