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 23HeaderRenderer::~HeaderRenderer() 24{ 25} 26 27 28void 29HeaderRenderer::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 54DefaultHeaderRenderer::DefaultHeaderRenderer() 55{ 56} 57 58 59DefaultHeaderRenderer::~DefaultHeaderRenderer() 60{ 61} 62 63 64float 65DefaultHeaderRenderer::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 82float 83DefaultHeaderRenderer::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 99void 100DefaultHeaderRenderer::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 121HeaderListener::~HeaderListener() 122{ 123} 124 125 126void 127HeaderListener::HeaderWidthChanged(Header* header) 128{ 129} 130 131 132void 133HeaderListener::HeaderWidthRestrictionsChanged(Header* header) 134{ 135} 136 137 138void 139HeaderListener::HeaderValueChanged(Header* header) 140{ 141} 142 143 144void 145HeaderListener::HeaderRendererChanged(Header* header) 146{ 147} 148 149 150// #pragma mark - Header 151 152 153Header::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 167Header::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 182float 183Header::Width() const 184{ 185 return fWidth; 186} 187 188 189float 190Header::MinWidth() const 191{ 192 return fMinWidth; 193} 194 195 196float 197Header::MaxWidth() const 198{ 199 return fMaxWidth; 200} 201 202 203float 204Header::PreferredWidth() const 205{ 206 return fPreferredWidth; 207} 208 209 210void 211Header::SetWidth(float width) 212{ 213 if (width != fWidth) { 214 fWidth = width; 215 NotifyWidthChanged(); 216 } 217} 218 219 220void 221Header::SetMinWidth(float width) 222{ 223 if (width != fMinWidth) { 224 fMinWidth = width; 225 NotifyWidthRestrictionsChanged(); 226 } 227} 228 229 230void 231Header::SetMaxWidth(float width) 232{ 233 if (width != fMaxWidth) { 234 fMaxWidth = width; 235 NotifyWidthRestrictionsChanged(); 236 } 237} 238 239 240void 241Header::SetPreferredWidth(float width) 242{ 243 if (width != fPreferredWidth) { 244 fPreferredWidth = width; 245 NotifyWidthRestrictionsChanged(); 246 } 247} 248 249 250bool 251Header::IsResizable() const 252{ 253 return fResizable; 254} 255 256 257void 258Header::SetResizable(bool resizable) 259{ 260 if (resizable != fResizable) { 261 fResizable = resizable; 262 NotifyWidthRestrictionsChanged(); 263 } 264} 265 266 267bool 268Header::GetValue(BVariant& _value) const 269{ 270 _value = fValue; 271 return true; 272} 273 274 275void 276Header::SetValue(const BVariant& value) 277{ 278 fValue = value; 279 NotifyValueChanged(); 280} 281 282 283int32 284Header::ModelIndex() const 285{ 286 return fModelIndex; 287} 288 289 290void 291Header::SetModelIndex(int32 index) 292{ 293 fModelIndex = index; 294} 295 296 297HeaderRenderer* 298Header::GetHeaderRenderer() const 299{ 300 return fRenderer; 301} 302 303 304void 305Header::SetHeaderRenderer(HeaderRenderer* renderer) 306{ 307 if (renderer != fRenderer) { 308 fRenderer = renderer; 309 NotifyRendererChanged(); 310 } 311} 312 313 314void 315Header::AddListener(HeaderListener* listener) 316{ 317 fListeners.AddItem(listener); 318} 319 320 321void 322Header::RemoveListener(HeaderListener* listener) 323{ 324 fListeners.RemoveItem(listener); 325} 326 327 328void 329Header::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 338void 339Header::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 348void 349Header::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 358void 359Header::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 371HeaderModelListener::~HeaderModelListener() 372{ 373} 374 375 376void 377HeaderModelListener::HeaderAdded(HeaderModel* model, int32 index) 378{ 379} 380 381 382void 383HeaderModelListener::HeaderRemoved(HeaderModel* model, int32 index) 384{ 385} 386 387 388void 389HeaderModelListener::HeaderMoved(HeaderModel* model, int32 fromIndex, 390 int32 toIndex) 391{ 392} 393 394 395// #pragma mark - HeaderModel 396 397 398HeaderModel::HeaderModel() 399{ 400} 401 402 403HeaderModel::~HeaderModel() 404{ 405} 406 407 408int32 409HeaderModel::CountHeaders() const 410{ 411 return fHeaders.CountItems(); 412} 413 414 415Header* 416HeaderModel::HeaderAt(int32 index) const 417{ 418 return fHeaders.ItemAt(index); 419} 420 421 422int32 423HeaderModel::IndexOfHeader(Header* header) const 424{ 425 return fHeaders.IndexOf(header); 426} 427 428 429bool 430HeaderModel::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 441Header* 442HeaderModel::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 454void 455HeaderModel::RemoveHeader(Header* header) 456{ 457 RemoveHeader(fHeaders.IndexOf(header)); 458} 459 460 461bool 462HeaderModel::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 483void 484HeaderModel::AddListener(HeaderModelListener* listener) 485{ 486 fListeners.AddItem(listener); 487} 488 489 490void 491HeaderModel::RemoveListener(HeaderModelListener* listener) 492{ 493 fListeners.RemoveItem(listener); 494} 495 496 497void 498HeaderModel::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 507void 508HeaderModel::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 517void 518HeaderModel::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 530struct 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 546class HeaderView::State { 547public: 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 579protected: 580 HeaderView* fParent; 581}; 582 583 584class HeaderView::DefaultState : public State { 585public: 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 595class HeaderView::ResizeState : public State { 596public: 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 608private: 609 Header* fHeader; 610 float fStartX; 611 float fStartWidth; 612}; 613 614 615// #pragma mark - DefaultState 616 617 618HeaderView::DefaultState::DefaultState(HeaderView* parent) 619 : 620 State(parent) 621{ 622} 623 624 625void 626HeaderView::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 660void 661HeaderView::DefaultState::MouseMoved(BPoint where, uint32 transit, 662 const BMessage* dragMessage) 663{ 664} 665 666 667// #pragma mark - ResizeState 668 669 670void 671HeaderView::ResizeState::Entering(State* previousState) 672{ 673 fParent->SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY); 674} 675 676 677void 678HeaderView::ResizeState::Leaving(State* nextState) 679{ 680 fParent->SetEventMask(0, 0); 681} 682 683 684HeaderView::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 695void 696HeaderView::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 704void 705HeaderView::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 718HeaderView::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 735HeaderView::~HeaderView() 736{ 737 SetModel(NULL); 738 739 _SwitchState(NULL); 740 delete fDefaultState; 741} 742 743 744void 745HeaderView::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 777BSize 778HeaderView::MinSize() 779{ 780 _ValidateHeadersLayout(); 781 782 return BLayoutUtils::ComposeSize(ExplicitMinSize(), 783 BSize(100, fPreferredHeight - 1)); 784} 785 786 787BSize 788HeaderView::MaxSize() 789{ 790 _ValidateHeadersLayout(); 791 792 return BLayoutUtils::ComposeSize(ExplicitMaxSize(), 793 BSize(B_SIZE_UNLIMITED, fPreferredHeight - 1)); 794} 795 796 797BSize 798HeaderView::PreferredSize() 799{ 800 _ValidateHeadersLayout(); 801 802 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), 803 BSize(fPreferredWidth - 1, fPreferredHeight - 1)); 804} 805 806 807HeaderModel* 808HeaderView::Model() const 809{ 810 return fModel; 811} 812 813 814void 815HeaderView::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 830void 831HeaderView::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 846void 847HeaderView::MouseMoved(BPoint where, uint32 transit, 848 const BMessage* dragMessage) 849{ 850 fState->MouseMoved(where, transit, dragMessage); 851} 852 853 854status_t 855HeaderView::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 899BRect 900HeaderView::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 913int32 914HeaderView::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 927void 928HeaderView::AddListener(HeaderViewListener* listener) 929{ 930 fListeners.AddItem(listener); 931} 932 933 934void 935HeaderView::RemoveListener(HeaderViewListener* listener) 936{ 937 fListeners.RemoveItem(listener); 938} 939 940 941void 942HeaderView::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 958void 959HeaderView::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 968void 969HeaderView::HeaderMoved(HeaderModel* model, int32 fromIndex, int32 toIndex) 970{ 971 _InvalidateHeadersLayout(std::min(fromIndex, toIndex)); 972} 973 974 975void 976HeaderView::HeaderWidthChanged(Header* header) 977{ 978 _HeaderPropertiesChanged(header, true, true); 979} 980 981 982void 983HeaderView::HeaderWidthRestrictionsChanged(Header* header) 984{ 985 // TODO:... 986} 987 988 989void 990HeaderView::HeaderValueChanged(Header* header) 991{ 992 _HeaderPropertiesChanged(header, true, false); 993} 994 995 996void 997HeaderView::HeaderRendererChanged(Header* header) 998{ 999 _HeaderPropertiesChanged(header, true, true); 1000} 1001 1002 1003void 1004HeaderView::_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 1019void 1020HeaderView::_InvalidateHeadersLayout(int32 firstIndex) 1021{ 1022 if (!fLayoutValid) 1023 return; 1024 1025 fLayoutValid = false; 1026 InvalidateLayout(); 1027 Invalidate(); 1028} 1029 1030 1031void 1032HeaderView::_InvalidateHeaders(int32 firstIndex, int32 endIndex) 1033{ 1034 Invalidate(); 1035 // TODO: Be less lazy! 1036} 1037 1038 1039void 1040HeaderView::_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 1078void 1079HeaderView::_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 1097HeaderViewListener::~HeaderViewListener() 1098{ 1099} 1100