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
~HeaderRenderer()23 HeaderRenderer::~HeaderRenderer()
24 {
25 }
26
27
28 void
DrawHeaderBackground(BView * view,BRect frame,BRect updateRect,uint32 flags)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
DefaultHeaderRenderer()54 DefaultHeaderRenderer::DefaultHeaderRenderer()
55 {
56 }
57
58
~DefaultHeaderRenderer()59 DefaultHeaderRenderer::~DefaultHeaderRenderer()
60 {
61 }
62
63
64 float
HeaderHeight(BView * view,const Header * header)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
PreferredHeaderWidth(BView * view,const Header * header)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
DrawHeader(BView * view,BRect frame,BRect updateRect,const Header * header,uint32 flags)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
~HeaderListener()121 HeaderListener::~HeaderListener()
122 {
123 }
124
125
126 void
HeaderWidthChanged(Header * header)127 HeaderListener::HeaderWidthChanged(Header* header)
128 {
129 }
130
131
132 void
HeaderWidthRestrictionsChanged(Header * header)133 HeaderListener::HeaderWidthRestrictionsChanged(Header* header)
134 {
135 }
136
137
138 void
HeaderValueChanged(Header * header)139 HeaderListener::HeaderValueChanged(Header* header)
140 {
141 }
142
143
144 void
HeaderRendererChanged(Header * header)145 HeaderListener::HeaderRendererChanged(Header* header)
146 {
147 }
148
149
150 // #pragma mark - Header
151
152
Header(int32 modelIndex)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
Header(float width,float minWidth,float maxWidth,float preferredWidth,int32 modelIndex)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
Width() const183 Header::Width() const
184 {
185 return fWidth;
186 }
187
188
189 float
MinWidth() const190 Header::MinWidth() const
191 {
192 return fMinWidth;
193 }
194
195
196 float
MaxWidth() const197 Header::MaxWidth() const
198 {
199 return fMaxWidth;
200 }
201
202
203 float
PreferredWidth() const204 Header::PreferredWidth() const
205 {
206 return fPreferredWidth;
207 }
208
209
210 void
SetWidth(float width)211 Header::SetWidth(float width)
212 {
213 if (width != fWidth) {
214 fWidth = width;
215 NotifyWidthChanged();
216 }
217 }
218
219
220 void
SetMinWidth(float width)221 Header::SetMinWidth(float width)
222 {
223 if (width != fMinWidth) {
224 fMinWidth = width;
225 NotifyWidthRestrictionsChanged();
226 }
227 }
228
229
230 void
SetMaxWidth(float width)231 Header::SetMaxWidth(float width)
232 {
233 if (width != fMaxWidth) {
234 fMaxWidth = width;
235 NotifyWidthRestrictionsChanged();
236 }
237 }
238
239
240 void
SetPreferredWidth(float width)241 Header::SetPreferredWidth(float width)
242 {
243 if (width != fPreferredWidth) {
244 fPreferredWidth = width;
245 NotifyWidthRestrictionsChanged();
246 }
247 }
248
249
250 bool
IsResizable() const251 Header::IsResizable() const
252 {
253 return fResizable;
254 }
255
256
257 void
SetResizable(bool resizable)258 Header::SetResizable(bool resizable)
259 {
260 if (resizable != fResizable) {
261 fResizable = resizable;
262 NotifyWidthRestrictionsChanged();
263 }
264 }
265
266
267 bool
GetValue(BVariant & _value) const268 Header::GetValue(BVariant& _value) const
269 {
270 _value = fValue;
271 return true;
272 }
273
274
275 void
SetValue(const BVariant & value)276 Header::SetValue(const BVariant& value)
277 {
278 fValue = value;
279 NotifyValueChanged();
280 }
281
282
283 int32
ModelIndex() const284 Header::ModelIndex() const
285 {
286 return fModelIndex;
287 }
288
289
290 void
SetModelIndex(int32 index)291 Header::SetModelIndex(int32 index)
292 {
293 fModelIndex = index;
294 }
295
296
297 HeaderRenderer*
GetHeaderRenderer() const298 Header::GetHeaderRenderer() const
299 {
300 return fRenderer;
301 }
302
303
304 void
SetHeaderRenderer(HeaderRenderer * renderer)305 Header::SetHeaderRenderer(HeaderRenderer* renderer)
306 {
307 if (renderer != fRenderer) {
308 fRenderer = renderer;
309 NotifyRendererChanged();
310 }
311 }
312
313
314 void
AddListener(HeaderListener * listener)315 Header::AddListener(HeaderListener* listener)
316 {
317 fListeners.AddItem(listener);
318 }
319
320
321 void
RemoveListener(HeaderListener * listener)322 Header::RemoveListener(HeaderListener* listener)
323 {
324 fListeners.RemoveItem(listener);
325 }
326
327
328 void
NotifyWidthChanged()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
NotifyWidthRestrictionsChanged()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
NotifyValueChanged()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
NotifyRendererChanged()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
~HeaderModelListener()371 HeaderModelListener::~HeaderModelListener()
372 {
373 }
374
375
376 void
HeaderAdded(HeaderModel * model,int32 index)377 HeaderModelListener::HeaderAdded(HeaderModel* model, int32 index)
378 {
379 }
380
381
382 void
HeaderRemoved(HeaderModel * model,int32 index)383 HeaderModelListener::HeaderRemoved(HeaderModel* model, int32 index)
384 {
385 }
386
387
388 void
HeaderMoved(HeaderModel * model,int32 fromIndex,int32 toIndex)389 HeaderModelListener::HeaderMoved(HeaderModel* model, int32 fromIndex,
390 int32 toIndex)
391 {
392 }
393
394
395 // #pragma mark - HeaderModel
396
397
HeaderModel()398 HeaderModel::HeaderModel()
399 {
400 }
401
402
~HeaderModel()403 HeaderModel::~HeaderModel()
404 {
405 }
406
407
408 int32
CountHeaders() const409 HeaderModel::CountHeaders() const
410 {
411 return fHeaders.CountItems();
412 }
413
414
415 Header*
HeaderAt(int32 index) const416 HeaderModel::HeaderAt(int32 index) const
417 {
418 return fHeaders.ItemAt(index);
419 }
420
421
422 int32
IndexOfHeader(Header * header) const423 HeaderModel::IndexOfHeader(Header* header) const
424 {
425 return fHeaders.IndexOf(header);
426 }
427
428
429 bool
AddHeader(Header * header)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*
RemoveHeader(int32 index)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
RemoveHeader(Header * header)455 HeaderModel::RemoveHeader(Header* header)
456 {
457 RemoveHeader(fHeaders.IndexOf(header));
458 }
459
460
461 bool
MoveHeader(int32 fromIndex,int32 toIndex)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
AddListener(HeaderModelListener * listener)484 HeaderModel::AddListener(HeaderModelListener* listener)
485 {
486 fListeners.AddItem(listener);
487 }
488
489
490 void
RemoveListener(HeaderModelListener * listener)491 HeaderModel::RemoveListener(HeaderModelListener* listener)
492 {
493 fListeners.RemoveItem(listener);
494 }
495
496
497 void
NotifyHeaderAdded(int32 index)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
NotifyHeaderRemoved(int32 index)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
NotifyHeaderMoved(int32 fromIndex,int32 toIndex)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
HeaderEntryHeaderView::HeaderEntry535 HeaderEntry(Header* header)
536 :
537 header(header)
538 {
539 }
540 };
541
542
543 // #pragma mark - States
544
545
546 class HeaderView::State {
547 public:
State(HeaderView * parent)548 State(HeaderView* parent)
549 :
550 fParent(parent)
551 {
552 }
553
~State()554 virtual ~State()
555 {
556 }
557
Entering(State * previousState)558 virtual void Entering(State* previousState)
559 {
560 }
561
Leaving(State * nextState)562 virtual void Leaving(State* nextState)
563 {
564 }
565
MouseDown(BPoint where,uint32 buttons,uint32 modifiers)566 virtual void MouseDown(BPoint where, uint32 buttons, uint32 modifiers)
567 {
568 }
569
MouseUp(BPoint where,uint32 buttons,uint32 modifiers)570 virtual void MouseUp(BPoint where, uint32 buttons, uint32 modifiers)
571 {
572 }
573
MouseMoved(BPoint where,uint32 transit,const BMessage * dragMessage)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
DefaultState(HeaderView * parent)618 HeaderView::DefaultState::DefaultState(HeaderView* parent)
619 :
620 State(parent)
621 {
622 }
623
624
625 void
MouseDown(BPoint where,uint32 buttons,uint32 modifiers)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
MouseMoved(BPoint where,uint32 transit,const BMessage * dragMessage)661 HeaderView::DefaultState::MouseMoved(BPoint where, uint32 transit,
662 const BMessage* dragMessage)
663 {
664 }
665
666
667 // #pragma mark - ResizeState
668
669
670 void
Entering(State * previousState)671 HeaderView::ResizeState::Entering(State* previousState)
672 {
673 fParent->SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
674 }
675
676
677 void
Leaving(State * nextState)678 HeaderView::ResizeState::Leaving(State* nextState)
679 {
680 fParent->SetEventMask(0, 0);
681 }
682
683
ResizeState(HeaderView * parent,int32 headerIndex,BPoint startPoint)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
MouseUp(BPoint where,uint32 buttons,uint32 modifiers)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
MouseMoved(BPoint where,uint32 transit,const BMessage * dragMessage)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
HeaderView()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
~HeaderView()735 HeaderView::~HeaderView()
736 {
737 SetModel(NULL);
738
739 _SwitchState(NULL);
740 delete fDefaultState;
741 }
742
743
744 void
Draw(BRect updateRect)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
MinSize()778 HeaderView::MinSize()
779 {
780 _ValidateHeadersLayout();
781
782 return BLayoutUtils::ComposeSize(ExplicitMinSize(),
783 BSize(100, fPreferredHeight - 1));
784 }
785
786
787 BSize
MaxSize()788 HeaderView::MaxSize()
789 {
790 _ValidateHeadersLayout();
791
792 return BLayoutUtils::ComposeSize(ExplicitMaxSize(),
793 BSize(B_SIZE_UNLIMITED, fPreferredHeight - 1));
794 }
795
796
797 BSize
PreferredSize()798 HeaderView::PreferredSize()
799 {
800 _ValidateHeadersLayout();
801
802 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(),
803 BSize(fPreferredWidth - 1, fPreferredHeight - 1));
804 }
805
806
807 HeaderModel*
Model() const808 HeaderView::Model() const
809 {
810 return fModel;
811 }
812
813
814 void
MouseDown(BPoint where)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
MouseUp(BPoint where)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
MouseMoved(BPoint where,uint32 transit,const BMessage * dragMessage)847 HeaderView::MouseMoved(BPoint where, uint32 transit,
848 const BMessage* dragMessage)
849 {
850 fState->MouseMoved(where, transit, dragMessage);
851 }
852
853
854 status_t
SetModel(HeaderModel * model)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
HeaderFrame(int32 index) const900 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
HeaderIndexAt(BPoint point) const914 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
AddListener(HeaderViewListener * listener)928 HeaderView::AddListener(HeaderViewListener* listener)
929 {
930 fListeners.AddItem(listener);
931 }
932
933
934 void
RemoveListener(HeaderViewListener * listener)935 HeaderView::RemoveListener(HeaderViewListener* listener)
936 {
937 fListeners.RemoveItem(listener);
938 }
939
940
941 void
HeaderAdded(HeaderModel * model,int32 index)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
HeaderRemoved(HeaderModel * model,int32 index)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
HeaderMoved(HeaderModel * model,int32 fromIndex,int32 toIndex)969 HeaderView::HeaderMoved(HeaderModel* model, int32 fromIndex, int32 toIndex)
970 {
971 _InvalidateHeadersLayout(std::min(fromIndex, toIndex));
972 }
973
974
975 void
HeaderWidthChanged(Header * header)976 HeaderView::HeaderWidthChanged(Header* header)
977 {
978 _HeaderPropertiesChanged(header, true, true);
979 }
980
981
982 void
HeaderWidthRestrictionsChanged(Header * header)983 HeaderView::HeaderWidthRestrictionsChanged(Header* header)
984 {
985 // TODO:...
986 }
987
988
989 void
HeaderValueChanged(Header * header)990 HeaderView::HeaderValueChanged(Header* header)
991 {
992 _HeaderPropertiesChanged(header, true, false);
993 }
994
995
996 void
HeaderRendererChanged(Header * header)997 HeaderView::HeaderRendererChanged(Header* header)
998 {
999 _HeaderPropertiesChanged(header, true, true);
1000 }
1001
1002
1003 void
_HeaderPropertiesChanged(Header * header,bool redrawNeeded,bool relayoutNeeded)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
_InvalidateHeadersLayout(int32 firstIndex)1020 HeaderView::_InvalidateHeadersLayout(int32 firstIndex)
1021 {
1022 if (!fLayoutValid)
1023 return;
1024
1025 fLayoutValid = false;
1026 InvalidateLayout();
1027 Invalidate();
1028 }
1029
1030
1031 void
_InvalidateHeaders(int32 firstIndex,int32 endIndex)1032 HeaderView::_InvalidateHeaders(int32 firstIndex, int32 endIndex)
1033 {
1034 Invalidate();
1035 // TODO: Be less lazy!
1036 }
1037
1038
1039 void
_ValidateHeadersLayout()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
_SwitchState(State * newState)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
~HeaderViewListener()1097 HeaderViewListener::~HeaderViewListener()
1098 {
1099 }
1100