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