xref: /haiku/src/apps/debuganalyzer/gui/chart/LineChartRenderer.cpp (revision 83b1a68c52ba3e0e8796282759f694b7fdddf06d)
1 /*
2  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "chart/LineChartRenderer.h"
7 
8 #include <stdio.h>
9 
10 #include <Shape.h>
11 #include <View.h>
12 
13 #include "chart/ChartDataSource.h"
14 
15 
16 // #pragma mark - DataSourceInfo
17 
18 
19 struct LineChartRenderer::DataSourceInfo {
20 public:
21 			ChartDataSource*	source;
22 			double*				samples;
23 			int32				sampleCount;
24 			bool				samplesValid;
25 			LineChartRendererDataSourceConfig config;
26 
27 public:
28 								DataSourceInfo(ChartDataSource* source,
29 									LineChartRendererDataSourceConfig* config);
30 								~DataSourceInfo();
31 
32 			bool				UpdateSamples(const ChartDataRange& domain,
33 									int32 sampleCount);
34 };
35 
36 
37 LineChartRenderer::DataSourceInfo::DataSourceInfo(ChartDataSource* source,
38 	LineChartRendererDataSourceConfig* config)
39 	:
40 	source(source),
41 	samples(NULL),
42 	sampleCount(0),
43 	samplesValid(false)
44 {
45 	if (config != NULL)
46 		this->config = *config;
47 }
48 
49 
50 LineChartRenderer::DataSourceInfo::~DataSourceInfo()
51 {
52 	delete[] samples;
53 }
54 
55 
56 bool
57 LineChartRenderer::DataSourceInfo::UpdateSamples(const ChartDataRange& domain,
58 	int32 sampleCount)
59 {
60 	if (samplesValid)
61 		return true;
62 
63 	// check the sample count -- we might need to realloc the sample array
64 	if (sampleCount != this->sampleCount) {
65 		delete[] samples;
66 		this->sampleCount = 0;
67 
68 		samples = new(std::nothrow) double[sampleCount];
69 		if (samples == NULL)
70 			return false;
71 
72 		this->sampleCount = sampleCount;
73 	}
74 
75 	// get the new samples
76 	source->GetSamples(domain.min, domain.max, samples, sampleCount);
77 
78 	samplesValid = true;
79 	return true;
80 }
81 
82 
83 // #pragma mark - LineChartRenderer
84 
85 
86 LineChartRenderer::LineChartRenderer()
87 	:
88 	fFrame(),
89 	fDomain(),
90 	fRange()
91 {
92 }
93 
94 
95 LineChartRenderer::~LineChartRenderer()
96 {
97 }
98 
99 
100 bool
101 LineChartRenderer::AddDataSource(ChartDataSource* dataSource, int32 index,
102 	ChartRendererDataSourceConfig* config)
103 {
104 	DataSourceInfo* info = new(std::nothrow) DataSourceInfo(dataSource,
105 		dynamic_cast<LineChartRendererDataSourceConfig*>(config));
106 	if (info == NULL)
107 		return false;
108 
109 	if (!fDataSources.AddItem(info, index)) {
110 		delete info;
111 		return false;
112 	}
113 
114 	return true;
115 }
116 
117 
118 void
119 LineChartRenderer::RemoveDataSource(ChartDataSource* dataSource)
120 {
121 	for (int32 i = 0; DataSourceInfo* info = fDataSources.ItemAt(i); i++) {
122 		info->samplesValid = false;
123 		if (info->source == dataSource) {
124 			delete fDataSources.RemoveItemAt(i);
125 			return;
126 		}
127 	}
128 }
129 
130 
131 void
132 LineChartRenderer::SetFrame(const BRect& frame)
133 {
134 	fFrame = frame;
135 	_InvalidateSamples();
136 }
137 
138 
139 void
140 LineChartRenderer::SetDomain(const ChartDataRange& domain)
141 {
142 	if (domain != fDomain) {
143 		fDomain = domain;
144 		_InvalidateSamples();
145 	}
146 }
147 
148 
149 void
150 LineChartRenderer::SetRange(const ChartDataRange& range)
151 {
152 	if (range != fRange) {
153 		fRange = range;
154 		_InvalidateSamples();
155 	}
156 }
157 
158 
159 void
160 LineChartRenderer::Render(BView* view, BRect updateRect)
161 {
162 	if (!updateRect.IsValid() || updateRect.left > fFrame.right
163 		|| fFrame.left > updateRect.right) {
164 		return;
165 	}
166 
167 	if (fDomain.min >= fDomain.max || fRange.min >= fRange.max)
168 		return;
169 
170 	if (!_UpdateSamples())
171 		return;
172 
173 	// get the range to draw (draw one more sample on each side)
174 	int32 left = (int32)fFrame.left;
175 	int32 first = (int32)updateRect.left - left - 1;
176 	int32 last = (int32)updateRect.right - left + 1;
177 	if (first < 0)
178 		first = 0;
179 	if (last > fFrame.IntegerWidth())
180 		last = fFrame.IntegerWidth();
181 	if (first > last)
182 		return;
183 
184 	double minRange = fRange.min;
185 	double sampleRange = fRange.max - minRange;
186 	if (sampleRange == 0) {
187 		minRange = fRange.min - 0.5;
188 		sampleRange = 1;
189 	}
190 	double scale = (double)fFrame.IntegerHeight() / sampleRange;
191 
192 	// draw
193 	view->SetLineMode(B_ROUND_CAP, B_ROUND_JOIN);
194 	for (int32 i = 0; DataSourceInfo* info = fDataSources.ItemAt(i); i++) {
195 
196 		float bottom = fFrame.bottom;
197 		BShape shape;
198 		shape.MoveTo(BPoint(left + first,
199 			bottom - ((info->samples[first] - minRange) * scale)));
200 
201 		for (int32 i = first; i <= last; i++) {
202 			shape.LineTo(BPoint(float(left + i),
203 				float(bottom - ((info->samples[i] - minRange) * scale))));
204 		}
205 		view->SetHighColor(info->config.Color());
206 		view->MovePenTo(B_ORIGIN);
207 		view->StrokeShape(&shape);
208 	}
209 }
210 
211 
212 void
213 LineChartRenderer::_InvalidateSamples()
214 {
215 	for (int32 i = 0; DataSourceInfo* info = fDataSources.ItemAt(i); i++)
216 		info->samplesValid = false;
217 }
218 
219 
220 bool
221 LineChartRenderer::_UpdateSamples()
222 {
223 	int32 width = fFrame.IntegerWidth() + 1;
224 	if (width <= 0)
225 		return false;
226 
227 	for (int32 i = 0; DataSourceInfo* info = fDataSources.ItemAt(i); i++) {
228 		if (!info->UpdateSamples(fDomain, width))
229 			return false;
230 	}
231 
232 	return true;
233 }
234 
235 
236 // #pragma mark - LineChartRendererDataSourceConfig
237 
238 
239 LineChartRendererDataSourceConfig::LineChartRendererDataSourceConfig()
240 {
241 	fColor.red = 0;
242 	fColor.green = 0;
243 	fColor.blue = 0;
244 	fColor.alpha = 255;
245 }
246 
247 
248 LineChartRendererDataSourceConfig::LineChartRendererDataSourceConfig(
249 	const rgb_color& color)
250 {
251 	fColor = color;
252 }
253 
254 
255 LineChartRendererDataSourceConfig::~LineChartRendererDataSourceConfig()
256 {
257 }
258 
259 
260 const rgb_color&
261 LineChartRendererDataSourceConfig::Color() const
262 {
263 	return fColor;
264 }
265 
266 
267 void
268 LineChartRendererDataSourceConfig::SetColor(const rgb_color& color)
269 {
270 	fColor = color;
271 }
272