1/*
2 * Copyright 2009, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Clemens Zeidler, haiku@clemens-zeidler.de
7 */
8
9#include "ColorStepView.h"
10
11#include <stdio.h>
12
13#include <Catalog.h>
14#include <Locale.h>
15#include <Window.h>
16
17
18#undef B_TRANSLATION_CONTEXT
19#define B_TRANSLATION_CONTEXT "Color Step View"
20
21
22const int32 kColorBarHeight = 15;
23
24const uint32 kMSGSliderChanged = '&slc';
25
26
27ColorStepView::ColorStepView(BRect frame)
28	: BControl(frame, "ColorStepView", "", new BMessage(kSteppingChanged),
29				B_FOLLOW_ALL, B_WILL_DRAW),
30	fOffScreenView(NULL),
31	fOffScreenBitmap(NULL)
32{
33	fPerformanceList = new PerformanceList(20, true);
34
35	fSliderPosition = 0;
36	fNSteps = 0;
37	fLowFreqColor.red = 0;
38	fLowFreqColor.blue = 255;
39	fLowFreqColor.green = 0;
40
41	fHighFreqColor.red = 255;
42	fHighFreqColor.blue = 0;
43	fHighFreqColor.green = 0;
44
45	fMinFrequencyLabel = "? MHz";
46	fMaxFrequencyLabel = "? MHz";
47	_InitView();
48}
49
50
51ColorStepView::~ColorStepView()
52{
53	delete fPerformanceList;
54}
55
56
57void
58ColorStepView::AttachedToWindow()
59{
60	fSlider->SetTarget(this);
61
62	if (!fOffScreenView) {
63		fOffScreenView = new BView(Bounds(), "", B_FOLLOW_ALL, B_WILL_DRAW);
64	}
65	if (!fOffScreenBitmap) {
66		fOffScreenBitmap = new BBitmap(Bounds(), B_CMAP8, true, false);
67		Window()->Lock();
68		if (fOffScreenBitmap && fOffScreenView)
69			fOffScreenBitmap->AddChild(fOffScreenView);
70		Window()->Unlock();
71	}
72}
73
74
75void
76ColorStepView::DetachedFromWindow()
77{
78	BView::DetachedFromWindow();
79
80	if (fOffScreenBitmap) {
81		delete fOffScreenBitmap;
82		fOffScreenBitmap = NULL;
83		fOffScreenView = NULL;
84	}
85}
86
87
88void
89ColorStepView::FrameResized(float w,float h)
90{
91	BView::FrameResized(w, h);
92
93	BRect bounds(Bounds());
94
95	if (bounds.right <= 0.0f || bounds.bottom <= 0.0f)
96		return;
97
98	if (fOffScreenBitmap) {
99		fOffScreenBitmap->RemoveChild(fOffScreenView);
100		delete fOffScreenBitmap;
101
102		fOffScreenView->ResizeTo(bounds.Width(), bounds.Height());
103
104		fOffScreenBitmap = new BBitmap(Bounds(), B_RGBA32, true, false);
105		fOffScreenBitmap->AddChild(fOffScreenView);
106	}
107
108	Invalidate();
109}
110
111
112void
113ColorStepView::GetPreferredSize(float *width, float *height)
114{
115	*width = Frame().Width();
116	font_height fontHeight;
117	GetFontHeight(&fontHeight);
118
119	*height = fSlider->Frame().Height();
120	*height += kColorBarHeight;
121	*height += fontHeight.descent + fontHeight.ascent + 5;
122}
123
124
125void
126ColorStepView::Draw(BRect updateRect)
127{
128	BView *view = NULL;
129	if(fOffScreenView){
130		view = fOffScreenView;
131	}
132	else{
133		view = this;
134	}
135
136	if (!fOffScreenBitmap || !fOffScreenBitmap->Lock())
137		return;
138	view->SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
139
140	view->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
141	view->FillRect(updateRect);
142
143	BRect colorBarRect =  fSlider->BarFrame();
144	colorBarRect.top = 0;
145	colorBarRect.bottom = kColorBarHeight;
146	colorBarRect.OffsetTo(colorBarRect.left, fSlider->Frame().bottom);
147
148	float pos = 0.0;
149	for (int i = fPerformanceList->CountItems() - 1; i >= 0 ; i--) {
150		performance_step* perfState = fPerformanceList->ItemAt(i);
151
152		float nextPos = perfState->cpu_usage;
153		float width = colorBarRect.Width();
154
155		BRect subRect(colorBarRect);
156		subRect.left += pos * width;
157		subRect.right = colorBarRect.left + nextPos * width;
158
159		view->SetHighColor(perfState->color);
160		view->FillRect(subRect);
161
162		pos = nextPos;
163	}
164	// draw label
165	if (IsEnabled()) {
166		view->SetHighColor(0, 0, 0);
167	} else {
168		view->SetHighColor(tint_color(LowColor(), B_DISABLED_LABEL_TINT));
169	}
170
171	font_height fontHeight;
172	GetFontHeight(&fontHeight);
173	float totalFontHeight = fontHeight.descent + fontHeight.ascent;
174
175	view->DrawString(fMinFrequencyLabel.String(),
176						BPoint(0.0,
177								colorBarRect.bottom + totalFontHeight + 5));
178
179	view->DrawString(fMaxFrequencyLabel.String(),
180						BPoint(Bounds().right
181								- StringWidth(fMaxFrequencyLabel.String()),
182								colorBarRect.bottom	+ totalFontHeight + 5));
183
184	// blit bitmap
185	view->Sync();
186	fOffScreenBitmap->Unlock();
187	DrawBitmap(fOffScreenBitmap, B_ORIGIN);
188
189	BView::Draw(updateRect);
190}
191
192
193void
194ColorStepView::MessageReceived(BMessage *message)
195{
196	switch (message->what) {
197		case kMSGSliderChanged:
198			fSliderPosition = fSlider->Position();
199			_CalculatePerformanceSteps();
200			Invalidate();
201			break;
202		case kSteppingChanged:
203			Invoke();
204			break;
205		default:
206			BView::MessageReceived(message);
207			break;
208	}
209}
210
211
212void
213ColorStepView::SetEnabled(bool enabled)
214{
215	fSlider->SetEnabled(enabled);
216	BControl::SetEnabled(enabled);
217}
218
219
220void
221ColorStepView::SetFrequencys(StateList *list)
222{
223	fStateList = list;
224	fNSteps = fStateList->CountItems();
225	if (fNSteps >= 2) {
226		float minFreq = fStateList->ItemAt(fNSteps - 1)->frequency;
227		float maxFreq = fStateList->ItemAt(0)->frequency;
228		fMinFrequencyLabel = CreateFrequencyString(minFreq);
229		fMaxFrequencyLabel = CreateFrequencyString(maxFreq);
230	}
231
232	// fit size of fPerformanceList
233	int32 perfNumber = fPerformanceList->CountItems();
234	if (perfNumber < fNSteps) {
235		for (int i = 0; i < fNSteps - perfNumber; i++)
236			fPerformanceList->AddItem(new performance_step);
237	}
238	else {
239		for (int i = 0; i <  perfNumber - fNSteps; i++)
240			fPerformanceList->RemoveItemAt(0);
241	}
242	// and fill the list
243	_CalculatePerformanceSteps();
244
245}
246
247
248PerformanceList*
249ColorStepView::GetPerformanceSteps()
250{
251	return fPerformanceList;
252}
253
254
255BString
256ColorStepView::CreateFrequencyString(uint16 frequency)
257{
258	BString string = "";
259	if (frequency >= 1000) {
260		char buffer [10];
261		sprintf (buffer, "%.1f", float(frequency) / 1000);
262		string << buffer;
263		string += " GHz";
264	}
265	else {
266		string << frequency;
267		string += " MHz";
268	}
269	return string;
270}
271
272
273
274float
275ColorStepView::UsageOfStep(int32 step, int32 nSteps, float base)
276{
277	float singleWidth = (1 - base) / (nSteps - 1);
278	return base + singleWidth * step;
279}
280
281
282void
283ColorStepView::_InitView()
284{
285	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
286
287	BRect sliderFrame(Bounds());
288
289	fSlider = new BSlider(sliderFrame, "StepSlider",
290							B_TRANSLATE("Step up by CPU usage"),
291							new BMessage(kSteppingChanged), 0, 100);
292	fSlider->SetModificationMessage(new BMessage(kMSGSliderChanged));
293
294	fSliderPosition = 0.25 - fNSteps * 0.05;
295	fSlider->SetPosition(fSliderPosition);
296	fSlider->SetLimitLabels("0%", "100%");
297	fSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
298	fSlider->SetHashMarkCount(5);
299	AddChild(fSlider);
300}
301
302
303void
304ColorStepView::_CalculatePerformanceSteps()
305{
306	for (int i = 0; i < fNSteps; i++) {
307		// begin with the lowest frequency
308		performance_step* perfState = fPerformanceList->ItemAt(fNSteps -1 - i);
309		perfState->cpu_usage = _PositonStep(i);
310		_ColorStep(i, perfState->color);
311	}
312}
313
314
315float
316ColorStepView::_PositonStep(int32 step)
317{
318	if (step >= fNSteps)
319		return 1.0;
320
321	return UsageOfStep(step, fNSteps, fSliderPosition);
322}
323
324
325void
326ColorStepView::_ColorStep(int32 step, rgb_color &color)
327{
328	color.red = fLowFreqColor.red
329					+ (fHighFreqColor.red - fLowFreqColor.red)
330						/ (fNSteps - 1) * step;
331	color.green = fLowFreqColor.green
332					+ (fHighFreqColor.green - fLowFreqColor.green)
333						/ (fNSteps - 1) * step;
334	color.blue = fLowFreqColor.blue
335					+ (fHighFreqColor.blue - fLowFreqColor.blue)
336						/ (fNSteps - 1) * step;
337}
338
339