xref: /haiku/src/apps/debuganalyzer/gui/chart/LegendChartAxis.cpp (revision 883b3e1d5cd632bb1a86def5d39a3eebf32ace13)
1bea425f1SIngo Weinhold /*
2bea425f1SIngo Weinhold  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3bea425f1SIngo Weinhold  * Distributed under the terms of the MIT License.
4bea425f1SIngo Weinhold  */
5bea425f1SIngo Weinhold 
6bea425f1SIngo Weinhold #include "chart/LegendChartAxis.h"
7bea425f1SIngo Weinhold 
8bea425f1SIngo Weinhold #include <limits.h>
9bea425f1SIngo Weinhold #include <stdio.h>
10bea425f1SIngo Weinhold 
11bea425f1SIngo Weinhold #include <algorithm>
12bea425f1SIngo Weinhold #include <new>
13bea425f1SIngo Weinhold 
14bea425f1SIngo Weinhold #include <Font.h>
15bea425f1SIngo Weinhold #include <View.h>
16bea425f1SIngo Weinhold 
17bea425f1SIngo Weinhold #include "chart/ChartLegend.h"
18bea425f1SIngo Weinhold #include "chart/ChartAxisLegendSource.h"
19bea425f1SIngo Weinhold 
20bea425f1SIngo Weinhold 
21bea425f1SIngo Weinhold static const int32 kChartRulerDistance = 2;
22bea425f1SIngo Weinhold static const int32 kRulerSize = 3;
23bea425f1SIngo Weinhold static const int32 kRulerMarkSize = 3;
24bea425f1SIngo Weinhold static const int32 kRulerLegendDistance = 2;
25bea425f1SIngo Weinhold static const int32 kChartLegendDistance
26bea425f1SIngo Weinhold 	= kChartRulerDistance + kRulerSize + kRulerMarkSize + kRulerLegendDistance;
27bea425f1SIngo Weinhold 
28bea425f1SIngo Weinhold 
29bea425f1SIngo Weinhold 
30bea425f1SIngo Weinhold struct LegendChartAxis::LegendInfo {
31bea425f1SIngo Weinhold 	ChartLegend*	legend;
32bea425f1SIngo Weinhold 	double			value;
33bea425f1SIngo Weinhold 	BSize			size;
34bea425f1SIngo Weinhold 
LegendInfoLegendChartAxis::LegendInfo35bea425f1SIngo Weinhold 	LegendInfo(ChartLegend* legend, double value, BSize size)
36bea425f1SIngo Weinhold 		:
37bea425f1SIngo Weinhold 		legend(legend),
38bea425f1SIngo Weinhold 		value(value),
39bea425f1SIngo Weinhold 		size(size)
40bea425f1SIngo Weinhold 	{
41bea425f1SIngo Weinhold 	}
42bea425f1SIngo Weinhold 
~LegendInfoLegendChartAxis::LegendInfo43bea425f1SIngo Weinhold 	~LegendInfo()
44bea425f1SIngo Weinhold 	{
45bea425f1SIngo Weinhold 		delete legend;
46bea425f1SIngo Weinhold 	}
47bea425f1SIngo Weinhold };
48bea425f1SIngo Weinhold 
49bea425f1SIngo Weinhold 
50bea425f1SIngo Weinhold float
_LegendPosition(double value,float legendSize,float totalSize,double scale)51bea425f1SIngo Weinhold LegendChartAxis::_LegendPosition(double value, float legendSize,
52bea425f1SIngo Weinhold 	float totalSize, double scale)
53bea425f1SIngo Weinhold {
54bea425f1SIngo Weinhold 	float position = (value - fRange.min) * scale - legendSize / 2;
55bea425f1SIngo Weinhold 	if (position + legendSize > totalSize)
56bea425f1SIngo Weinhold 		position = totalSize - legendSize;
57bea425f1SIngo Weinhold 	if (position < 0)
58bea425f1SIngo Weinhold 		position = 0;
59bea425f1SIngo Weinhold 	return position;
60bea425f1SIngo Weinhold }
61bea425f1SIngo Weinhold 
62bea425f1SIngo Weinhold 
63bea425f1SIngo Weinhold void
_FilterLegends(int32 totalSize,int32 spacing,float BSize::* sizeField)64bea425f1SIngo Weinhold LegendChartAxis::_FilterLegends(int32 totalSize, int32 spacing,
65bea425f1SIngo Weinhold 	float BSize::* sizeField)
66bea425f1SIngo Weinhold {
67bea425f1SIngo Weinhold 	// compute the min/max legend levels
68bea425f1SIngo Weinhold 	int32 legendCount = fLegends.CountItems();
69bea425f1SIngo Weinhold 	int32 minLevel = INT_MAX;
70bea425f1SIngo Weinhold 	int32 maxLevel = 0;
71bea425f1SIngo Weinhold 
72bea425f1SIngo Weinhold 	for (int32 i = 0; i < legendCount; i++) {
73bea425f1SIngo Weinhold 		LegendInfo* info = fLegends.ItemAt(i);
74bea425f1SIngo Weinhold 		int32 level = info->legend->Level();
75bea425f1SIngo Weinhold 		if (level < minLevel)
76bea425f1SIngo Weinhold 			minLevel = level;
77bea425f1SIngo Weinhold 		if (level > maxLevel)
78bea425f1SIngo Weinhold 			maxLevel = level;
79bea425f1SIngo Weinhold 	}
80bea425f1SIngo Weinhold 
81bea425f1SIngo Weinhold 	if (maxLevel <= 0)
82bea425f1SIngo Weinhold 		return;
83bea425f1SIngo Weinhold 
84bea425f1SIngo Weinhold 	double rangeSize = fRange.max - fRange.min;
85bea425f1SIngo Weinhold 	if (rangeSize == 0)
86bea425f1SIngo Weinhold 		rangeSize = 1.0;
87bea425f1SIngo Weinhold 	double scale = (double)totalSize / rangeSize;
88bea425f1SIngo Weinhold 
89bea425f1SIngo Weinhold 	// Filter out all higher level legends colliding with lower level or
90bea425f1SIngo Weinhold 	// preceeding same-level legends. We iterate backwards from the lower to
91bea425f1SIngo Weinhold 	// the higher levels
92*883b3e1dSMichael Lotz 	for (int32 level = std::max(minLevel, (int32)0); level <= maxLevel;) {
93bea425f1SIngo Weinhold 		legendCount = fLegends.CountItems();
94bea425f1SIngo Weinhold 
95bea425f1SIngo Weinhold 		// get the first legend position/end
96bea425f1SIngo Weinhold 		LegendInfo* info = fLegends.ItemAt(0);
97bea425f1SIngo Weinhold 		float position = _LegendPosition(info->value, info->size.*sizeField,
98bea425f1SIngo Weinhold 			(float)totalSize, scale);;
99bea425f1SIngo Weinhold 
100bea425f1SIngo Weinhold 		int32 previousEnd = (int32)ceilf(position + info->size.*sizeField);
101bea425f1SIngo Weinhold 		int32 previousLevel = info->legend->Level();
102bea425f1SIngo Weinhold 
103bea425f1SIngo Weinhold 		for (int32 i = 1; (info = fLegends.ItemAt(i)) != NULL; i++) {
104bea425f1SIngo Weinhold 			float position = _LegendPosition(info->value, info->size.*sizeField,
105bea425f1SIngo Weinhold 				(float)totalSize, scale);;
106bea425f1SIngo Weinhold 
107bea425f1SIngo Weinhold 			if (position - spacing < previousEnd
108bea425f1SIngo Weinhold 				&& (previousLevel <= level
109bea425f1SIngo Weinhold 					|| info->legend->Level() <= level)
110bea425f1SIngo Weinhold 				&& std::max(previousLevel, info->legend->Level()) > 0) {
111bea425f1SIngo Weinhold 				// The item intersects with the previous one -- remove the
112bea425f1SIngo Weinhold 				// one at the higher level.
113bea425f1SIngo Weinhold 				if (info->legend->Level() >= previousLevel) {
114bea425f1SIngo Weinhold 					// This item is at the higher level -- remove it.
115bea425f1SIngo Weinhold 					delete fLegends.RemoveItemAt(i);
116bea425f1SIngo Weinhold 					i--;
117bea425f1SIngo Weinhold 					continue;
118bea425f1SIngo Weinhold 				}
119bea425f1SIngo Weinhold 
120bea425f1SIngo Weinhold 				// The previous item is at the higher level -- remove it.
121bea425f1SIngo Weinhold 				delete fLegends.RemoveItemAt(i - 1);
122bea425f1SIngo Weinhold 				i--;
123bea425f1SIngo Weinhold 			}
124bea425f1SIngo Weinhold 
125bea425f1SIngo Weinhold 			if (i == 0 && position < 0)
126bea425f1SIngo Weinhold 				position = 0;
127bea425f1SIngo Weinhold 			previousEnd = (int32)ceilf(position + info->size.*sizeField);
128bea425f1SIngo Weinhold 			previousLevel = info->legend->Level();
129bea425f1SIngo Weinhold 		}
130bea425f1SIngo Weinhold 
131bea425f1SIngo Weinhold 		// repeat with the level as long as we've removed something
132bea425f1SIngo Weinhold 		if (legendCount == fLegends.CountItems())
133bea425f1SIngo Weinhold 			level++;
134bea425f1SIngo Weinhold 	}
135bea425f1SIngo Weinhold }
136bea425f1SIngo Weinhold 
137bea425f1SIngo Weinhold 
LegendChartAxis(ChartAxisLegendSource * legendSource,ChartLegendRenderer * legendRenderer)138bea425f1SIngo Weinhold LegendChartAxis::LegendChartAxis(ChartAxisLegendSource* legendSource,
139bea425f1SIngo Weinhold 	ChartLegendRenderer* legendRenderer)
140bea425f1SIngo Weinhold 	:
141bea425f1SIngo Weinhold 	fLegendSource(legendSource),
142bea425f1SIngo Weinhold 	fLegendRenderer(legendRenderer),
143bea425f1SIngo Weinhold 	fLocation(CHART_AXIS_BOTTOM),
144bea425f1SIngo Weinhold 	fRange(),
145bea425f1SIngo Weinhold 	fFrame(),
146bea425f1SIngo Weinhold 	fLegends(20, true),
147bea425f1SIngo Weinhold 	fHorizontalSpacing(20),
148bea425f1SIngo Weinhold 	fVerticalSpacing(10),
149bea425f1SIngo Weinhold 	fLayoutValid(false)
150bea425f1SIngo Weinhold {
151bea425f1SIngo Weinhold }
152bea425f1SIngo Weinhold 
153bea425f1SIngo Weinhold 
~LegendChartAxis()154bea425f1SIngo Weinhold LegendChartAxis::~LegendChartAxis()
155bea425f1SIngo Weinhold {
156bea425f1SIngo Weinhold }
157bea425f1SIngo Weinhold 
158bea425f1SIngo Weinhold 
159bea425f1SIngo Weinhold void
SetLocation(ChartAxisLocation location)160bea425f1SIngo Weinhold LegendChartAxis::SetLocation(ChartAxisLocation location)
161bea425f1SIngo Weinhold {
162bea425f1SIngo Weinhold 	if (location != fLocation) {
163bea425f1SIngo Weinhold 		fLocation = location;
164bea425f1SIngo Weinhold 		_InvalidateLayout();
165bea425f1SIngo Weinhold 	}
166bea425f1SIngo Weinhold }
167bea425f1SIngo Weinhold 
168bea425f1SIngo Weinhold 
169bea425f1SIngo Weinhold void
SetRange(const ChartDataRange & range)170bea425f1SIngo Weinhold LegendChartAxis::SetRange(const ChartDataRange& range)
171bea425f1SIngo Weinhold {
172bea425f1SIngo Weinhold 	if (range != fRange) {
173bea425f1SIngo Weinhold 		fRange = range;
174bea425f1SIngo Weinhold 		_InvalidateLayout();
175bea425f1SIngo Weinhold 	}
176bea425f1SIngo Weinhold }
177bea425f1SIngo Weinhold 
178bea425f1SIngo Weinhold 
179bea425f1SIngo Weinhold void
SetFrame(BRect frame)180bea425f1SIngo Weinhold LegendChartAxis::SetFrame(BRect frame)
181bea425f1SIngo Weinhold {
182bea425f1SIngo Weinhold 	if (frame != fFrame) {
183bea425f1SIngo Weinhold 		fFrame = frame;
184bea425f1SIngo Weinhold 		_InvalidateLayout();
185bea425f1SIngo Weinhold 	}
186bea425f1SIngo Weinhold }
187bea425f1SIngo Weinhold 
188bea425f1SIngo Weinhold 
189bea425f1SIngo Weinhold BSize
PreferredSize(BView * view,BSize maxSize)190314f0e01SIngo Weinhold LegendChartAxis::PreferredSize(BView* view, BSize maxSize)
191bea425f1SIngo Weinhold {
192314f0e01SIngo Weinhold 	// estimate the maximum legend count we might need
193314f0e01SIngo Weinhold 	float hSpacing, vSpacing;
194314f0e01SIngo Weinhold 	int32 maxLegends = _EstimateMaxLegendCount(view, maxSize, &hSpacing,
195314f0e01SIngo Weinhold 		&vSpacing);
196314f0e01SIngo Weinhold 	BSize spacing(hSpacing, vSpacing);
197314f0e01SIngo Weinhold 	if (maxLegends < 4)
198314f0e01SIngo Weinhold 		maxLegends = 4;
199314f0e01SIngo Weinhold 
200314f0e01SIngo Weinhold 	// get the legends
201314f0e01SIngo Weinhold 	ChartLegend* legends[maxLegends];
202314f0e01SIngo Weinhold 	double values[maxLegends];
203314f0e01SIngo Weinhold 
204314f0e01SIngo Weinhold 	int32 legendCount = fLegendSource->GetAxisLegends(fRange, legends, values,
205314f0e01SIngo Weinhold 		maxLegends);
206314f0e01SIngo Weinhold 
207314f0e01SIngo Weinhold 	// get the sizes, delete the legends, and compute the preferred size
208314f0e01SIngo Weinhold 	float BSize::* sizeField;
209314f0e01SIngo Weinhold 	float BSize::* otherSizeField;
210bea425f1SIngo Weinhold 	if (fLocation == CHART_AXIS_LEFT || fLocation == CHART_AXIS_RIGHT) {
211314f0e01SIngo Weinhold 		sizeField = &BSize::height;
212314f0e01SIngo Weinhold 		otherSizeField = &BSize::width;
213bea425f1SIngo Weinhold 	} else {
214314f0e01SIngo Weinhold 		sizeField = &BSize::width;
215314f0e01SIngo Weinhold 		otherSizeField = &BSize::height;
216bea425f1SIngo Weinhold 	}
217bea425f1SIngo Weinhold 
218314f0e01SIngo Weinhold 	BSize preferredSize;
219314f0e01SIngo Weinhold 
220314f0e01SIngo Weinhold 	for (int32 i = 0; i < legendCount; i++) {
221314f0e01SIngo Weinhold 		ChartLegend* legend = legends[i];
222314f0e01SIngo Weinhold 		BSize size = fLegendRenderer->LegendSize(legend, view);
223314f0e01SIngo Weinhold 		delete legend;
224314f0e01SIngo Weinhold 
225314f0e01SIngo Weinhold 		if (size.*sizeField > preferredSize.*sizeField)
226314f0e01SIngo Weinhold 			preferredSize.*sizeField = size.*sizeField;
227314f0e01SIngo Weinhold 		if (size.*otherSizeField > preferredSize.*otherSizeField)
228314f0e01SIngo Weinhold 			preferredSize.*otherSizeField = size.*otherSizeField;
229314f0e01SIngo Weinhold 	}
230314f0e01SIngo Weinhold 
231314f0e01SIngo Weinhold 	// Suppose we want to have at least 2 legends.
232314f0e01SIngo Weinhold 	preferredSize.*sizeField
233314f0e01SIngo Weinhold 		= ceilf(preferredSize.*sizeField * 2 + spacing.*sizeField);
234314f0e01SIngo Weinhold 	preferredSize.*otherSizeField += kChartLegendDistance;
235314f0e01SIngo Weinhold 
236314f0e01SIngo Weinhold 	return preferredSize;
237bea425f1SIngo Weinhold }
238bea425f1SIngo Weinhold 
239bea425f1SIngo Weinhold 
240bea425f1SIngo Weinhold void
Render(BView * view,BRect updateRect)241bea425f1SIngo Weinhold LegendChartAxis::Render(BView* view, BRect updateRect)
242bea425f1SIngo Weinhold {
243bea425f1SIngo Weinhold 	if (!_ValidateLayout(view))
244bea425f1SIngo Weinhold 		return;
245bea425f1SIngo Weinhold 
246b8c273deSIngo Weinhold 	float valueDirection;
247b8c273deSIngo Weinhold 	float rulerDirection;
248b8c273deSIngo Weinhold 	float BSize::* sizeField;
249b8c273deSIngo Weinhold 	float BSize::* otherSizeField;
250b8c273deSIngo Weinhold 	float BPoint::* pointField;
251b8c273deSIngo Weinhold 	float BPoint::* otherPointField;
252b8c273deSIngo Weinhold 
253b8c273deSIngo Weinhold 	switch (fLocation) {
254b8c273deSIngo Weinhold 		case CHART_AXIS_LEFT:
255b8c273deSIngo Weinhold 		case CHART_AXIS_RIGHT:
256b8c273deSIngo Weinhold 			valueDirection = -1;
257b8c273deSIngo Weinhold 			rulerDirection = fLocation == CHART_AXIS_LEFT ? -1 : 1;
258b8c273deSIngo Weinhold 			sizeField = &BSize::height;
259b8c273deSIngo Weinhold 			otherSizeField = &BSize::width;
260b8c273deSIngo Weinhold 			pointField = &BPoint::y;
261b8c273deSIngo Weinhold 			otherPointField = &BPoint::x;
262b8c273deSIngo Weinhold 			break;
263b8c273deSIngo Weinhold 		case CHART_AXIS_TOP:
264b8c273deSIngo Weinhold 		case CHART_AXIS_BOTTOM:
265b8c273deSIngo Weinhold 			valueDirection = 1;
266b8c273deSIngo Weinhold 			rulerDirection = fLocation == CHART_AXIS_TOP ? -1 : 1;
267b8c273deSIngo Weinhold 			sizeField = &BSize::width;
268b8c273deSIngo Weinhold 			otherSizeField = &BSize::height;
269b8c273deSIngo Weinhold 			pointField = &BPoint::x;
270b8c273deSIngo Weinhold 			otherPointField = &BPoint::y;
271b8c273deSIngo Weinhold 			break;
272b8c273deSIngo Weinhold 		default:
273b8c273deSIngo Weinhold 			return;
274b8c273deSIngo Weinhold 	}
275b8c273deSIngo Weinhold 
276b8c273deSIngo Weinhold 	float totalSize = floorf(fFrame.Size().*sizeField) + 1;
277bea425f1SIngo Weinhold 	double rangeSize = fRange.max - fRange.min;
278bea425f1SIngo Weinhold 	if (rangeSize == 0)
279bea425f1SIngo Weinhold 		rangeSize = 1.0;
280bea425f1SIngo Weinhold 	double scale = (double)totalSize / rangeSize;
281bea425f1SIngo Weinhold 
282bea425f1SIngo Weinhold 	// draw the ruler
283b8c273deSIngo Weinhold 	float rulerStart = fFrame.LeftBottom().*pointField;
284b8c273deSIngo Weinhold 	float rulerChartClosest = rulerDirection == 1
285b8c273deSIngo Weinhold 		? fFrame.LeftTop().*otherPointField + kChartRulerDistance
286b8c273deSIngo Weinhold 		: fFrame.RightBottom().*otherPointField - kChartRulerDistance;
287b8c273deSIngo Weinhold 	float rulerEnd = fFrame.RightTop().*pointField;
288b8c273deSIngo Weinhold 	float rulerChartDistant = rulerChartClosest + rulerDirection * kRulerSize;
289bea425f1SIngo Weinhold 
290bea425f1SIngo Weinhold 	rgb_color black = { 0, 0, 0, 255 };
291bea425f1SIngo Weinhold 	view->BeginLineArray(3 + fLegends.CountItems());
292b8c273deSIngo Weinhold 	BPoint first;
293b8c273deSIngo Weinhold 	first.*pointField = rulerStart;
294b8c273deSIngo Weinhold 	first.*otherPointField = rulerChartClosest;
295b8c273deSIngo Weinhold 	BPoint second = first;
296b8c273deSIngo Weinhold 	second.*otherPointField = rulerChartDistant;
297b8c273deSIngo Weinhold 	BPoint third = second;
298b8c273deSIngo Weinhold 	third.*pointField = rulerEnd;
299b8c273deSIngo Weinhold 	BPoint fourth = third;
300b8c273deSIngo Weinhold 	fourth.*otherPointField = rulerChartClosest;
301b8c273deSIngo Weinhold 	view->AddLine(first, second, black);
302b8c273deSIngo Weinhold 	view->AddLine(second, third, black);
303b8c273deSIngo Weinhold 	view->AddLine(third, fourth, black);
304bea425f1SIngo Weinhold 
305bea425f1SIngo Weinhold 	// marks
306bea425f1SIngo Weinhold 	for (int32 i = 0; LegendInfo* info = fLegends.ItemAt(i); i++) {
307bea425f1SIngo Weinhold 		float position = (info->value - fRange.min) * scale;
308b8c273deSIngo Weinhold 		position = rulerStart + valueDirection * position;
309b8c273deSIngo Weinhold 		first.*pointField = position;
310b8c273deSIngo Weinhold 		first.*otherPointField = rulerChartDistant;
311b8c273deSIngo Weinhold 		second.*pointField = position;
312b8c273deSIngo Weinhold 		second.*otherPointField = rulerChartDistant
313b8c273deSIngo Weinhold 			+ rulerDirection * kRulerMarkSize;
314b8c273deSIngo Weinhold 		view->AddLine(first, second, black);
315bea425f1SIngo Weinhold 	}
316bea425f1SIngo Weinhold 	view->EndLineArray();
317bea425f1SIngo Weinhold 
318bea425f1SIngo Weinhold 	// draw the legends
319b8c273deSIngo Weinhold 	float legendRulerClosest = rulerChartDistant
320b8c273deSIngo Weinhold 		+ rulerDirection * (kRulerMarkSize + kRulerLegendDistance);
321bea425f1SIngo Weinhold 
322bea425f1SIngo Weinhold 	for (int32 i = 0; LegendInfo* info = fLegends.ItemAt(i); i++) {
323bea425f1SIngo Weinhold 		float position = _LegendPosition(info->value, info->size.*sizeField,
324bea425f1SIngo Weinhold 			(float)totalSize, scale);;
325bea425f1SIngo Weinhold 
326b8c273deSIngo Weinhold 		first.*pointField = rulerStart
327b8c273deSIngo Weinhold 			+ (valueDirection == 1
328b8c273deSIngo Weinhold 				? position : -position - info->size.*sizeField);
329b8c273deSIngo Weinhold 		first.*otherPointField = rulerDirection == 1
330b8c273deSIngo Weinhold 			? legendRulerClosest
331b8c273deSIngo Weinhold 			: legendRulerClosest - info->size.*otherSizeField;
332b8c273deSIngo Weinhold 
333b8c273deSIngo Weinhold 		fLegendRenderer->RenderLegend(info->legend, view, first);
334bea425f1SIngo Weinhold 	}
335bea425f1SIngo Weinhold }
336bea425f1SIngo Weinhold 
337bea425f1SIngo Weinhold 
338bea425f1SIngo Weinhold void
_InvalidateLayout()339bea425f1SIngo Weinhold LegendChartAxis::_InvalidateLayout()
340bea425f1SIngo Weinhold {
341bea425f1SIngo Weinhold 	fLayoutValid = false;
342bea425f1SIngo Weinhold }
343bea425f1SIngo Weinhold 
344bea425f1SIngo Weinhold 
345bea425f1SIngo Weinhold bool
_ValidateLayout(BView * view)346bea425f1SIngo Weinhold LegendChartAxis::_ValidateLayout(BView* view)
347bea425f1SIngo Weinhold {
348bea425f1SIngo Weinhold 	if (fLayoutValid)
349bea425f1SIngo Weinhold 		return true;
350bea425f1SIngo Weinhold 
351bea425f1SIngo Weinhold 	fLegends.MakeEmpty();
352bea425f1SIngo Weinhold 
353bea425f1SIngo Weinhold 	int32 width = fFrame.IntegerWidth() + 1;
354bea425f1SIngo Weinhold 	int32 height = fFrame.IntegerHeight() + 1;
355bea425f1SIngo Weinhold 
356bea425f1SIngo Weinhold 	// estimate the maximum legend count we might need
357314f0e01SIngo Weinhold 	int32 maxLegends = _EstimateMaxLegendCount(view, fFrame.Size(),
358314f0e01SIngo Weinhold 		&fHorizontalSpacing, &fVerticalSpacing);
359bea425f1SIngo Weinhold 
360bea425f1SIngo Weinhold 	if (maxLegends == 0)
361bea425f1SIngo Weinhold 		return false;
362bea425f1SIngo Weinhold 
363bea425f1SIngo Weinhold 	// get the legends
364bea425f1SIngo Weinhold 	ChartLegend* legends[maxLegends];
365bea425f1SIngo Weinhold 	double values[maxLegends];
366bea425f1SIngo Weinhold 
367bea425f1SIngo Weinhold 	int32 legendCount = fLegendSource->GetAxisLegends(fRange, legends, values,
368bea425f1SIngo Weinhold 		maxLegends);
369bea425f1SIngo Weinhold 	if (legendCount == 0)
370bea425f1SIngo Weinhold 		return false;
371bea425f1SIngo Weinhold 
372bea425f1SIngo Weinhold 	// create legend infos
373bea425f1SIngo Weinhold 	for (int32 i = 0; i < legendCount; i++) {
374bea425f1SIngo Weinhold 		ChartLegend* legend = legends[i];
375bea425f1SIngo Weinhold 		BSize size = fLegendRenderer->LegendSize(legend, view);
376bea425f1SIngo Weinhold 		LegendInfo* info = new(std::nothrow) LegendInfo(legend, values[i],
377bea425f1SIngo Weinhold 			size);
378bea425f1SIngo Weinhold 		if (info == NULL || !fLegends.AddItem(info)) {
379bea425f1SIngo Weinhold 			// TODO: Report error!
380bea425f1SIngo Weinhold 			delete info;
381bea425f1SIngo Weinhold 			for (int32 k = i; k < legendCount; k++)
382bea425f1SIngo Weinhold 				delete legends[k];
383bea425f1SIngo Weinhold 			return false;
384bea425f1SIngo Weinhold 		}
385bea425f1SIngo Weinhold 	}
386bea425f1SIngo Weinhold 
387bea425f1SIngo Weinhold 	if (fLocation == CHART_AXIS_LEFT || fLocation == CHART_AXIS_RIGHT)
388bea425f1SIngo Weinhold 		_FilterLegends(height, fVerticalSpacing, &BSize::height);
389bea425f1SIngo Weinhold 	else
390bea425f1SIngo Weinhold 		_FilterLegends(width, fHorizontalSpacing, &BSize::width);
391bea425f1SIngo Weinhold 
392bea425f1SIngo Weinhold 	fLayoutValid = true;
393bea425f1SIngo Weinhold 	return true;
394bea425f1SIngo Weinhold }
395314f0e01SIngo Weinhold 
396314f0e01SIngo Weinhold 
397314f0e01SIngo Weinhold int32
_EstimateMaxLegendCount(BView * view,BSize size,float * _hSpacing,float * _vSpacing)398314f0e01SIngo Weinhold LegendChartAxis::_EstimateMaxLegendCount(BView* view, BSize size,
399314f0e01SIngo Weinhold 	float* _hSpacing, float* _vSpacing)
400314f0e01SIngo Weinhold {
401314f0e01SIngo Weinhold 	// get the legend spacing
402314f0e01SIngo Weinhold 	fLegendRenderer->GetMinimumLegendSpacing(view, _hSpacing, _vSpacing);
403314f0e01SIngo Weinhold 
404314f0e01SIngo Weinhold 	// estimate the maximum legend count we might need
405314f0e01SIngo Weinhold 	if (fLocation == CHART_AXIS_LEFT || fLocation == CHART_AXIS_RIGHT)
406b237fdf9SStephan Aßmus 		return (int32)((size.IntegerHeight() + 1) / (10 + *_vSpacing));
407b237fdf9SStephan Aßmus 	return (int32)((size.IntegerWidth() + 1) / (20 + *_hSpacing));
408314f0e01SIngo Weinhold }
409