1 /* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2009, Stephan Aßmus, superstippi@gmx.de. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include "HeaderView.h" 9 10 #include <stdio.h> 11 12 #include <algorithm> 13 #include <new> 14 15 #include <ControlLook.h> 16 #include <LayoutUtils.h> 17 #include <Looper.h> 18 19 20 // #pragma mark - HeaderRenderer 21 22 23 HeaderRenderer::~HeaderRenderer() 24 { 25 } 26 27 28 void 29 HeaderRenderer::DrawHeaderBackground(BView* view, BRect frame, BRect updateRect, 30 uint32 flags) 31 { 32 BRect bgRect = frame; 33 34 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 35 view->SetHighColor(tint_color(base, B_DARKEN_2_TINT)); 36 view->StrokeLine(bgRect.LeftBottom(), bgRect.RightBottom()); 37 38 bgRect.bottom--; 39 bgRect.right--; 40 41 // if ((flags & CLICKED) != 0) 42 // base = tint_color(base, B_DARKEN_1_TINT); 43 44 be_control_look->DrawButtonBackground(view, bgRect, updateRect, base, 0, 45 BControlLook::B_TOP_BORDER | BControlLook::B_BOTTOM_BORDER); 46 47 view->StrokeLine(frame.RightTop(), frame.RightBottom()); 48 } 49 50 51 // #pragma mark - DefaultHeaderRenderer 52 53 54 DefaultHeaderRenderer::DefaultHeaderRenderer() 55 { 56 } 57 58 59 DefaultHeaderRenderer::~DefaultHeaderRenderer() 60 { 61 } 62 63 64 float 65 DefaultHeaderRenderer::HeaderHeight(BView* view, const Header* header) 66 { 67 BVariant value; 68 if (!header->GetValue(value)) 69 return 0; 70 71 if (value.Type() == B_STRING_TYPE) { 72 font_height fontHeight; 73 view->GetFontHeight(&fontHeight); 74 return ceilf((fontHeight.ascent + fontHeight.descent) * 1.2f) + 2.0f; 75 } else { 76 // TODO: Support more value types. 77 return 0; 78 } 79 } 80 81 82 float 83 DefaultHeaderRenderer::PreferredHeaderWidth(BView* view, const Header* header) 84 { 85 BVariant value; 86 if (!header->GetValue(value)) 87 return 0; 88 89 if (value.Type() == B_STRING_TYPE) { 90 float width = view->StringWidth(value.ToString()); 91 return width + be_control_look->DefaultLabelSpacing() * 2.0f; 92 } else { 93 // TODO: Support more value types. 94 return 0; 95 } 96 } 97 98 99 void 100 DefaultHeaderRenderer::DrawHeader(BView* view, BRect frame, BRect updateRect, 101 const Header* header, uint32 flags) 102 { 103 DrawHeaderBackground(view, frame, updateRect, flags); 104 105 BVariant value; 106 if (!header->GetValue(value)) 107 return; 108 109 frame.InsetBy(be_control_look->DefaultLabelSpacing(), 0); 110 111 if (value.Type() == B_STRING_TYPE) { 112 be_control_look->DrawLabel(view, value.ToString(), frame, updateRect, 113 view->LowColor(), 0); 114 } 115 } 116 117 118 // #pragma mark - HeaderListener 119 120 121 HeaderListener::~HeaderListener() 122 { 123 } 124 125 126 void 127 HeaderListener::HeaderWidthChanged(Header* header) 128 { 129 } 130 131 132 void 133 HeaderListener::HeaderWidthRestrictionsChanged(Header* header) 134 { 135 } 136 137 138 void 139 HeaderListener::HeaderValueChanged(Header* header) 140 { 141 } 142 143 144 void 145 HeaderListener::HeaderRendererChanged(Header* header) 146 { 147 } 148 149 150 // #pragma mark - Header 151 152 153 Header::Header(int32 modelIndex) 154 : 155 fWidth(100), 156 fMinWidth(0), 157 fMaxWidth(10000), 158 fPreferredWidth(100), 159 fValue(), 160 fRenderer(NULL), 161 fModelIndex(modelIndex), 162 fResizable(true) 163 { 164 } 165 166 167 Header::Header(float width, float minWidth, float maxWidth, 168 float preferredWidth, int32 modelIndex) 169 : 170 fWidth(width), 171 fMinWidth(minWidth), 172 fMaxWidth(maxWidth), 173 fPreferredWidth(preferredWidth), 174 fValue(), 175 fRenderer(NULL), 176 fModelIndex(modelIndex), 177 fResizable(true) 178 { 179 } 180 181 182 float 183 Header::Width() const 184 { 185 return fWidth; 186 } 187 188 189 float 190 Header::MinWidth() const 191 { 192 return fMinWidth; 193 } 194 195 196 float 197 Header::MaxWidth() const 198 { 199 return fMaxWidth; 200 } 201 202 203 float 204 Header::PreferredWidth() const 205 { 206 return fPreferredWidth; 207 } 208 209 210 void 211 Header::SetWidth(float width) 212 { 213 if (width != fWidth) { 214 fWidth = width; 215 NotifyWidthChanged(); 216 } 217 } 218 219 220 void 221 Header::SetMinWidth(float width) 222 { 223 if (width != fMinWidth) { 224 fMinWidth = width; 225 NotifyWidthRestrictionsChanged(); 226 } 227 } 228 229 230 void 231 Header::SetMaxWidth(float width) 232 { 233 if (width != fMaxWidth) { 234 fMaxWidth = width; 235 NotifyWidthRestrictionsChanged(); 236 } 237 } 238 239 240 void 241 Header::SetPreferredWidth(float width) 242 { 243 if (width != fPreferredWidth) { 244 fPreferredWidth = width; 245 NotifyWidthRestrictionsChanged(); 246 } 247 } 248 249 250 bool 251 Header::IsResizable() const 252 { 253 return fResizable; 254 } 255 256 257 void 258 Header::SetResizable(bool resizable) 259 { 260 if (resizable != fResizable) { 261 fResizable = resizable; 262 NotifyWidthRestrictionsChanged(); 263 } 264 } 265 266 267 bool 268 Header::GetValue(BVariant& _value) const 269 { 270 _value = fValue; 271 return true; 272 } 273 274 275 void 276 Header::SetValue(const BVariant& value) 277 { 278 fValue = value; 279 NotifyValueChanged(); 280 } 281 282 283 int32 284 Header::ModelIndex() const 285 { 286 return fModelIndex; 287 } 288 289 290 void 291 Header::SetModelIndex(int32 index) 292 { 293 fModelIndex = index; 294 } 295 296 297 HeaderRenderer* 298 Header::GetHeaderRenderer() const 299 { 300 return fRenderer; 301 } 302 303 304 void 305 Header::SetHeaderRenderer(HeaderRenderer* renderer) 306 { 307 if (renderer != fRenderer) { 308 fRenderer = renderer; 309 NotifyRendererChanged(); 310 } 311 } 312 313 314 void 315 Header::AddListener(HeaderListener* listener) 316 { 317 fListeners.AddItem(listener); 318 } 319 320 321 void 322 Header::RemoveListener(HeaderListener* listener) 323 { 324 fListeners.RemoveItem(listener); 325 } 326 327 328 void 329 Header::NotifyWidthChanged() 330 { 331 for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) { 332 HeaderListener* listener = fListeners.ItemAt(i); 333 listener->HeaderWidthChanged(this); 334 } 335 } 336 337 338 void 339 Header::NotifyWidthRestrictionsChanged() 340 { 341 for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) { 342 HeaderListener* listener = fListeners.ItemAt(i); 343 listener->HeaderWidthRestrictionsChanged(this); 344 } 345 } 346 347 348 void 349 Header::NotifyValueChanged() 350 { 351 for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) { 352 HeaderListener* listener = fListeners.ItemAt(i); 353 listener->HeaderValueChanged(this); 354 } 355 } 356 357 358 void 359 Header::NotifyRendererChanged() 360 { 361 for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) { 362 HeaderListener* listener = fListeners.ItemAt(i); 363 listener->HeaderRendererChanged(this); 364 } 365 } 366 367 368 // #pragma mark - HeaderModelListener 369 370 371 HeaderModelListener::~HeaderModelListener() 372 { 373 } 374 375 376 void 377 HeaderModelListener::HeaderAdded(HeaderModel* model, int32 index) 378 { 379 } 380 381 382 void 383 HeaderModelListener::HeaderRemoved(HeaderModel* model, int32 index) 384 { 385 } 386 387 388 void 389 HeaderModelListener::HeaderMoved(HeaderModel* model, int32 fromIndex, 390 int32 toIndex) 391 { 392 } 393 394 395 // #pragma mark - HeaderModel 396 397 398 HeaderModel::HeaderModel() 399 { 400 } 401 402 403 HeaderModel::~HeaderModel() 404 { 405 } 406 407 408 int32 409 HeaderModel::CountHeaders() const 410 { 411 return fHeaders.CountItems(); 412 } 413 414 415 Header* 416 HeaderModel::HeaderAt(int32 index) const 417 { 418 return fHeaders.ItemAt(index); 419 } 420 421 422 int32 423 HeaderModel::IndexOfHeader(Header* header) const 424 { 425 return fHeaders.IndexOf(header); 426 } 427 428 429 bool 430 HeaderModel::AddHeader(Header* header) 431 { 432 if (!fHeaders.AddItem(header)) 433 return false; 434 435 NotifyHeaderAdded(fHeaders.CountItems() - 1); 436 437 return true; 438 } 439 440 441 Header* 442 HeaderModel::RemoveHeader(int32 index) 443 { 444 Header* header = fHeaders.RemoveItemAt(index); 445 if (header != NULL) 446 return NULL; 447 448 NotifyHeaderRemoved(index); 449 450 return header; 451 } 452 453 454 void 455 HeaderModel::RemoveHeader(Header* header) 456 { 457 RemoveHeader(fHeaders.IndexOf(header)); 458 } 459 460 461 bool 462 HeaderModel::MoveHeader(int32 fromIndex, int32 toIndex) 463 { 464 int32 headerCount = fHeaders.CountItems(); 465 if (fromIndex < 0 || fromIndex >= headerCount 466 || toIndex < 0 || toIndex >= headerCount) { 467 return false; 468 } 469 470 if (fromIndex == toIndex) 471 return true; 472 473 Header* header = fHeaders.RemoveItemAt(fromIndex); 474 fHeaders.AddItem(header, toIndex); 475 // TODO: Might fail. 476 477 NotifyHeaderMoved(fromIndex, toIndex); 478 479 return true; 480 } 481 482 483 void 484 HeaderModel::AddListener(HeaderModelListener* listener) 485 { 486 fListeners.AddItem(listener); 487 } 488 489 490 void 491 HeaderModel::RemoveListener(HeaderModelListener* listener) 492 { 493 fListeners.RemoveItem(listener); 494 } 495 496 497 void 498 HeaderModel::NotifyHeaderAdded(int32 index) 499 { 500 for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) { 501 HeaderModelListener* listener = fListeners.ItemAt(i); 502 listener->HeaderAdded(this, index); 503 } 504 } 505 506 507 void 508 HeaderModel::NotifyHeaderRemoved(int32 index) 509 { 510 for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) { 511 HeaderModelListener* listener = fListeners.ItemAt(i); 512 listener->HeaderRemoved(this, index); 513 } 514 } 515 516 517 void 518 HeaderModel::NotifyHeaderMoved(int32 fromIndex, int32 toIndex) 519 { 520 for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) { 521 HeaderModelListener* listener = fListeners.ItemAt(i); 522 listener->HeaderMoved(this, fromIndex, toIndex); 523 } 524 } 525 526 527 // #pragma mark - HeaderEntry 528 529 530 struct HeaderView::HeaderEntry { 531 Header* header; 532 float position; 533 float width; 534 535 HeaderEntry(Header* header) 536 : 537 header(header) 538 { 539 } 540 }; 541 542 543 // #pragma mark - States 544 545 546 class HeaderView::State { 547 public: 548 State(HeaderView* parent) 549 : 550 fParent(parent) 551 { 552 } 553 554 virtual ~State() 555 { 556 } 557 558 virtual void Entering(State* previousState) 559 { 560 } 561 562 virtual void Leaving(State* nextState) 563 { 564 } 565 566 virtual void MouseDown(BPoint where, uint32 buttons, uint32 modifiers) 567 { 568 } 569 570 virtual void MouseUp(BPoint where, uint32 buttons, uint32 modifiers) 571 { 572 } 573 574 virtual void MouseMoved(BPoint where, uint32 transit, 575 const BMessage* dragMessage) 576 { 577 } 578 579 protected: 580 HeaderView* fParent; 581 }; 582 583 584 class HeaderView::DefaultState : public State { 585 public: 586 DefaultState(HeaderView* parent); 587 588 virtual void MouseDown(BPoint where, uint32 buttons, 589 uint32 modifiers); 590 virtual void MouseMoved(BPoint where, uint32 transit, 591 const BMessage* dragMessage); 592 }; 593 594 595 class HeaderView::ResizeState : public State { 596 public: 597 virtual void Entering(State* previousState); 598 virtual void Leaving(State* nextState); 599 600 ResizeState(HeaderView* parent, 601 int32 headerIndex, BPoint startPoint); 602 603 virtual void MouseUp(BPoint where, uint32 buttons, 604 uint32 modifiers); 605 virtual void MouseMoved(BPoint where, uint32 transit, 606 const BMessage* dragMessage); 607 608 private: 609 Header* fHeader; 610 float fStartX; 611 float fStartWidth; 612 }; 613 614 615 // #pragma mark - DefaultState 616 617 618 HeaderView::DefaultState::DefaultState(HeaderView* parent) 619 : 620 State(parent) 621 { 622 } 623 624 625 void 626 HeaderView::DefaultState::MouseDown(BPoint where, uint32 buttons, 627 uint32 modifiers) 628 { 629 HeaderModel* model = fParent->Model(); 630 if (model == NULL) 631 return; 632 633 if ((buttons & B_PRIMARY_MOUSE_BUTTON) == 0) 634 return; 635 636 int32 headerIndex = fParent->HeaderIndexAt(where); 637 if (headerIndex < 0) { 638 int32 headerCount = model->CountHeaders(); 639 if (headerCount == 0) 640 return; 641 642 headerIndex = headerCount - 1; 643 } 644 645 // Check whether the mouse is close to the left or the right side of the 646 // header. 647 BRect headerFrame = fParent->HeaderFrame(headerIndex); 648 if (fabs(headerFrame.left - where.x) <= 3) { 649 if (headerIndex == 0) 650 return; 651 headerIndex--; 652 } else if (fabs(headerFrame.right + 1 - where.x) > 3) 653 return; 654 655 // start resizing the header 656 fParent->_SwitchState(new ResizeState(fParent, headerIndex, where)); 657 } 658 659 660 void 661 HeaderView::DefaultState::MouseMoved(BPoint where, uint32 transit, 662 const BMessage* dragMessage) 663 { 664 } 665 666 667 // #pragma mark - ResizeState 668 669 670 void 671 HeaderView::ResizeState::Entering(State* previousState) 672 { 673 fParent->SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY); 674 } 675 676 677 void 678 HeaderView::ResizeState::Leaving(State* nextState) 679 { 680 fParent->SetEventMask(0, 0); 681 } 682 683 684 HeaderView::ResizeState::ResizeState(HeaderView* parent, int32 headerIndex, 685 BPoint startPoint) 686 : 687 State(parent), 688 fHeader(parent->Model()->HeaderAt(headerIndex)), 689 fStartX(startPoint.x), 690 fStartWidth(fHeader->Width()) 691 { 692 } 693 694 695 void 696 HeaderView::ResizeState::MouseUp(BPoint where, uint32 buttons, 697 uint32 modifiers) 698 { 699 if ((buttons & B_PRIMARY_MOUSE_BUTTON) == 0) 700 fParent->_SwitchState(NULL); 701 } 702 703 704 void 705 HeaderView::ResizeState::MouseMoved(BPoint where, uint32 transit, 706 const BMessage* dragMessage) 707 { 708 float width = fStartWidth + where.x - fStartX; 709 width = std::max(width, fHeader->MinWidth()); 710 width = std::min(width, fHeader->MaxWidth()); 711 fHeader->SetWidth(width); 712 } 713 714 715 // #pragma mark - HeaderView 716 717 718 HeaderView::HeaderView() 719 : 720 BView("header view", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE), 721 fModel(NULL), 722 fHeaderEntries(10, true), 723 fLayoutValid(false), 724 fDefaultState(new DefaultState(this)), 725 fState(fDefaultState) 726 { 727 HeaderModel* model = new(std::nothrow) HeaderModel; 728 BReference<HeaderModel> modelReference(model, true); 729 SetModel(model); 730 731 SetViewColor(B_TRANSPARENT_32_BIT); 732 } 733 734 735 HeaderView::~HeaderView() 736 { 737 SetModel(NULL); 738 739 _SwitchState(NULL); 740 delete fDefaultState; 741 } 742 743 744 void 745 HeaderView::Draw(BRect updateRect) 746 { 747 if (fModel == NULL) 748 return; 749 750 _ValidateHeadersLayout(); 751 752 DefaultHeaderRenderer defaultRenderer; 753 float bottom = Bounds().Height(); 754 float left = 0.0f; 755 756 for (int32 i = 0; HeaderEntry* entry = fHeaderEntries.ItemAt(i); i++) { 757 if (Header* header = fModel->HeaderAt(i)) { 758 HeaderRenderer* renderer = header->GetHeaderRenderer(); 759 if (renderer == NULL) 760 renderer = &defaultRenderer; 761 762 BRect frame(entry->position, 0, entry->position + entry->width - 1, 763 bottom); 764 renderer->DrawHeader(this, frame, updateRect, header, 0); 765 // TODO: flags! 766 767 left = entry->position + entry->width; 768 } 769 } 770 771 // TODO: We are not using any custom renderer here. 772 defaultRenderer.DrawHeaderBackground(this, 773 BRect(left, 0, Bounds().right + 1, bottom), updateRect, 0); 774 } 775 776 777 BSize 778 HeaderView::MinSize() 779 { 780 _ValidateHeadersLayout(); 781 782 return BLayoutUtils::ComposeSize(ExplicitMinSize(), 783 BSize(100, fPreferredHeight - 1)); 784 } 785 786 787 BSize 788 HeaderView::MaxSize() 789 { 790 _ValidateHeadersLayout(); 791 792 return BLayoutUtils::ComposeSize(ExplicitMaxSize(), 793 BSize(B_SIZE_UNLIMITED, fPreferredHeight - 1)); 794 } 795 796 797 BSize 798 HeaderView::PreferredSize() 799 { 800 _ValidateHeadersLayout(); 801 802 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), 803 BSize(fPreferredWidth - 1, fPreferredHeight - 1)); 804 } 805 806 807 HeaderModel* 808 HeaderView::Model() const 809 { 810 return fModel; 811 } 812 813 814 void 815 HeaderView::MouseDown(BPoint where) 816 { 817 // get buttons and modifiers 818 BMessage* message = Looper()->CurrentMessage(); 819 int32 buttons; 820 if (message == NULL || message->FindInt32("buttons", &buttons) != B_OK) 821 buttons = 0; 822 int32 modifiers; 823 if (message == NULL || message->FindInt32("modifiers", &modifiers) != B_OK) 824 modifiers = 0; 825 826 fState->MouseDown(where, buttons, modifiers); 827 } 828 829 830 void 831 HeaderView::MouseUp(BPoint where) 832 { 833 // get buttons and modifiers 834 BMessage* message = Looper()->CurrentMessage(); 835 int32 buttons; 836 if (message == NULL || message->FindInt32("buttons", &buttons) != B_OK) 837 buttons = 0; 838 int32 modifiers; 839 if (message == NULL || message->FindInt32("modifiers", &modifiers) != B_OK) 840 modifiers = 0; 841 842 fState->MouseUp(where, buttons, modifiers); 843 } 844 845 846 void 847 HeaderView::MouseMoved(BPoint where, uint32 transit, 848 const BMessage* dragMessage) 849 { 850 fState->MouseMoved(where, transit, dragMessage); 851 } 852 853 854 status_t 855 HeaderView::SetModel(HeaderModel* model) 856 { 857 if (model == fModel) 858 return B_OK; 859 860 _SwitchState(NULL); 861 862 if (fModel != NULL) { 863 // remove all headers 864 for (int32 i = 0; HeaderEntry* entry = fHeaderEntries.ItemAt(i); i++) 865 entry->header->RemoveListener(this); 866 fHeaderEntries.MakeEmpty(); 867 868 fModel->RemoveListener(this); 869 fModel->ReleaseReference(); 870 } 871 872 fModel = model; 873 874 if (fModel != NULL) { 875 fModel->AcquireReference(); 876 fModel->AddListener(this); 877 878 // create header entries 879 int32 headerCount = fModel->CountHeaders(); 880 for (int32 i = 0; i < headerCount; i++) { 881 HeaderEntry* entry = new(std::nothrow) HeaderEntry( 882 fModel->HeaderAt(i)); 883 if (entry == NULL || !fHeaderEntries.AddItem(entry)) { 884 delete entry; 885 return B_NO_MEMORY; 886 } 887 888 entry->header->AddListener(this); 889 } 890 } 891 892 _InvalidateHeadersLayout(0); 893 Invalidate(); 894 895 return B_OK; 896 } 897 898 899 BRect 900 HeaderView::HeaderFrame(int32 index) const 901 { 902 float bottom = Bounds().Height(); 903 904 if (HeaderEntry* entry = fHeaderEntries.ItemAt(index)) { 905 return BRect(entry->position, 0, entry->position + entry->width - 1, 906 bottom); 907 } 908 909 return BRect(); 910 } 911 912 913 int32 914 HeaderView::HeaderIndexAt(BPoint point) const 915 { 916 float x = point.x; 917 918 for (int32 i = 0; HeaderEntry* entry = fHeaderEntries.ItemAt(i); i++) { 919 if (x >= entry->position && x < entry->position + entry->width) 920 return i; 921 } 922 923 return -1; 924 } 925 926 927 void 928 HeaderView::AddListener(HeaderViewListener* listener) 929 { 930 fListeners.AddItem(listener); 931 } 932 933 934 void 935 HeaderView::RemoveListener(HeaderViewListener* listener) 936 { 937 fListeners.RemoveItem(listener); 938 } 939 940 941 void 942 HeaderView::HeaderAdded(HeaderModel* model, int32 index) 943 { 944 if (Header* header = fModel->HeaderAt(index)) { 945 HeaderEntry* entry = new(std::nothrow) HeaderEntry( 946 fModel->HeaderAt(index)); 947 if (entry == NULL || !fHeaderEntries.AddItem(entry)) { 948 delete entry; 949 return; 950 } 951 952 header->AddListener(this); 953 _InvalidateHeadersLayout(index); 954 } 955 } 956 957 958 void 959 HeaderView::HeaderRemoved(HeaderModel* model, int32 index) 960 { 961 if (HeaderEntry* entry = fHeaderEntries.RemoveItemAt(index)) { 962 entry->header->RemoveListener(this); 963 _InvalidateHeadersLayout(index); 964 } 965 } 966 967 968 void 969 HeaderView::HeaderMoved(HeaderModel* model, int32 fromIndex, int32 toIndex) 970 { 971 _InvalidateHeadersLayout(std::min(fromIndex, toIndex)); 972 } 973 974 975 void 976 HeaderView::HeaderWidthChanged(Header* header) 977 { 978 _HeaderPropertiesChanged(header, true, true); 979 } 980 981 982 void 983 HeaderView::HeaderWidthRestrictionsChanged(Header* header) 984 { 985 // TODO:... 986 } 987 988 989 void 990 HeaderView::HeaderValueChanged(Header* header) 991 { 992 _HeaderPropertiesChanged(header, true, false); 993 } 994 995 996 void 997 HeaderView::HeaderRendererChanged(Header* header) 998 { 999 _HeaderPropertiesChanged(header, true, true); 1000 } 1001 1002 1003 void 1004 HeaderView::_HeaderPropertiesChanged(Header* header, bool redrawNeeded, 1005 bool relayoutNeeded) 1006 { 1007 if (!redrawNeeded && !relayoutNeeded) 1008 return; 1009 1010 int32 index = fModel->IndexOfHeader(header); 1011 1012 if (relayoutNeeded) 1013 _InvalidateHeadersLayout(index); 1014 else if (redrawNeeded) 1015 _InvalidateHeaders(index, index + 1); 1016 } 1017 1018 1019 void 1020 HeaderView::_InvalidateHeadersLayout(int32 firstIndex) 1021 { 1022 if (!fLayoutValid) 1023 return; 1024 1025 fLayoutValid = false; 1026 InvalidateLayout(); 1027 Invalidate(); 1028 } 1029 1030 1031 void 1032 HeaderView::_InvalidateHeaders(int32 firstIndex, int32 endIndex) 1033 { 1034 Invalidate(); 1035 // TODO: Be less lazy! 1036 } 1037 1038 1039 void 1040 HeaderView::_ValidateHeadersLayout() 1041 { 1042 if (fLayoutValid) 1043 return; 1044 1045 DefaultHeaderRenderer defaultRenderer; 1046 1047 int32 headerCount = fHeaderEntries.CountItems(); 1048 float position = 0; 1049 fPreferredWidth = 0; 1050 fPreferredHeight = 0; 1051 1052 for (int32 i = 0; i < headerCount; i++) { 1053 HeaderEntry* entry = fHeaderEntries.ItemAt(i); 1054 entry->position = position; 1055 if (Header* header = fModel->HeaderAt(i)) { 1056 entry->width = header->Width(); 1057 fPreferredWidth += header->PreferredWidth(); 1058 } else 1059 entry->width = 0; 1060 1061 position = entry->position + entry->width; 1062 1063 if (Header* header = fModel->HeaderAt(i)) { 1064 HeaderRenderer* renderer = header->GetHeaderRenderer(); 1065 if (renderer == NULL) 1066 renderer = &defaultRenderer; 1067 1068 float height = renderer->HeaderHeight(this, header); 1069 if (height > fPreferredHeight) 1070 fPreferredHeight = height; 1071 } 1072 } 1073 1074 fLayoutValid = true; 1075 } 1076 1077 1078 void 1079 HeaderView::_SwitchState(State* newState) 1080 { 1081 if (newState == NULL) 1082 newState = fDefaultState; 1083 1084 fState->Leaving(newState); 1085 newState->Entering(fState); 1086 1087 if (fState != fDefaultState) 1088 delete fState; 1089 1090 fState = newState; 1091 } 1092 1093 1094 // #pragma mark - HeaderViewListener 1095 1096 1097 HeaderViewListener::~HeaderViewListener() 1098 { 1099 } 1100