xref: /haiku/src/apps/activitymonitor/ActivityView.cpp (revision 230e32592636776ac911283b85f5e17ed2f7375c)
118d3e65eSAxel Dörfler /*
218d3e65eSAxel Dörfler  * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
318d3e65eSAxel Dörfler  * Distributed under the terms of the MIT License.
418d3e65eSAxel Dörfler  */
518d3e65eSAxel Dörfler 
618d3e65eSAxel Dörfler 
718d3e65eSAxel Dörfler #include "ActivityView.h"
818d3e65eSAxel Dörfler 
918d3e65eSAxel Dörfler #include <new>
1018d3e65eSAxel Dörfler #include <stdio.h>
1118d3e65eSAxel Dörfler #include <stdlib.h>
1218d3e65eSAxel Dörfler 
13dc1ffc79SFrançois Revol #ifdef __HAIKU__
14065e8de0SAxel Dörfler #	include <AbstractLayoutItem.h>
15dc1ffc79SFrançois Revol #endif
1618d3e65eSAxel Dörfler #include <Application.h>
17d4216445SAxel Dörfler #include <Autolock.h>
1818d3e65eSAxel Dörfler #include <Bitmap.h>
1918d3e65eSAxel Dörfler #include <Dragger.h>
2018d3e65eSAxel Dörfler #include <MenuItem.h>
2118d3e65eSAxel Dörfler #include <MessageRunner.h>
2218d3e65eSAxel Dörfler #include <PopUpMenu.h>
2318d3e65eSAxel Dörfler #include <String.h>
2418d3e65eSAxel Dörfler 
2518d3e65eSAxel Dörfler #include "ActivityMonitor.h"
263f315b26SAxel Dörfler #include "ActivityWindow.h"
2718d3e65eSAxel Dörfler #include "SystemInfo.h"
2874158bb4SFrançois Revol #include "SystemInfoHandler.h"
2918d3e65eSAxel Dörfler 
3018d3e65eSAxel Dörfler 
3151591198SAxel Dörfler class Scale {
3251591198SAxel Dörfler public:
3351591198SAxel Dörfler 							Scale(scale_type type);
3451591198SAxel Dörfler 
3551591198SAxel Dörfler 			int64			MinimumValue() const { return fMinimumValue; }
3651591198SAxel Dörfler 			int64			MaximumValue() const { return fMaximumValue; }
3751591198SAxel Dörfler 
3851591198SAxel Dörfler 			void			Update(int64 value);
3951591198SAxel Dörfler 
4051591198SAxel Dörfler private:
4151591198SAxel Dörfler 	scale_type				fType;
4251591198SAxel Dörfler 	int64					fMinimumValue;
4351591198SAxel Dörfler 	int64					fMaximumValue;
4451591198SAxel Dörfler 	bool					fInitialized;
4551591198SAxel Dörfler };
4651591198SAxel Dörfler 
4718d3e65eSAxel Dörfler struct data_item {
4818d3e65eSAxel Dörfler 	bigtime_t	time;
4918d3e65eSAxel Dörfler 	int64		value;
5018d3e65eSAxel Dörfler };
5118d3e65eSAxel Dörfler 
52dc1ffc79SFrançois Revol #ifdef __HAIKU__
53065e8de0SAxel Dörfler class ActivityView::HistoryLayoutItem : public BAbstractLayoutItem {
54065e8de0SAxel Dörfler public:
55065e8de0SAxel Dörfler 							HistoryLayoutItem(ActivityView* parent);
56065e8de0SAxel Dörfler 
57065e8de0SAxel Dörfler 	virtual	bool			IsVisible();
58065e8de0SAxel Dörfler 	virtual	void			SetVisible(bool visible);
59065e8de0SAxel Dörfler 
60065e8de0SAxel Dörfler 	virtual	BRect			Frame();
61065e8de0SAxel Dörfler 	virtual	void			SetFrame(BRect frame);
62065e8de0SAxel Dörfler 
63065e8de0SAxel Dörfler 	virtual	BView*			View();
64065e8de0SAxel Dörfler 
65065e8de0SAxel Dörfler 	virtual	BSize			BasePreferredSize();
66065e8de0SAxel Dörfler 
67065e8de0SAxel Dörfler private:
68065e8de0SAxel Dörfler 	ActivityView*			fParent;
69065e8de0SAxel Dörfler 	BRect					fFrame;
70065e8de0SAxel Dörfler };
71065e8de0SAxel Dörfler 
72065e8de0SAxel Dörfler class ActivityView::LegendLayoutItem : public BAbstractLayoutItem {
73065e8de0SAxel Dörfler public:
74065e8de0SAxel Dörfler 							LegendLayoutItem(ActivityView* parent);
75065e8de0SAxel Dörfler 
76065e8de0SAxel Dörfler 	virtual	bool			IsVisible();
77065e8de0SAxel Dörfler 	virtual	void			SetVisible(bool visible);
78065e8de0SAxel Dörfler 
79065e8de0SAxel Dörfler 	virtual	BRect			Frame();
80065e8de0SAxel Dörfler 	virtual	void			SetFrame(BRect frame);
81065e8de0SAxel Dörfler 
82065e8de0SAxel Dörfler 	virtual	BView*			View();
83065e8de0SAxel Dörfler 
84065e8de0SAxel Dörfler 	virtual	BSize			BaseMinSize();
85065e8de0SAxel Dörfler 	virtual	BSize			BaseMaxSize();
86065e8de0SAxel Dörfler 	virtual	BSize			BasePreferredSize();
87065e8de0SAxel Dörfler 	virtual	BAlignment		BaseAlignment();
88065e8de0SAxel Dörfler 
89065e8de0SAxel Dörfler private:
90065e8de0SAxel Dörfler 	ActivityView*			fParent;
91065e8de0SAxel Dörfler 	BRect					fFrame;
92065e8de0SAxel Dörfler };
93dc1ffc79SFrançois Revol #endif
94065e8de0SAxel Dörfler 
9518d3e65eSAxel Dörfler const bigtime_t kInitialRefreshInterval = 500000LL;
9618d3e65eSAxel Dörfler 
9718d3e65eSAxel Dörfler const uint32 kMsgToggleDataSource = 'tgds';
983a4a2141SAxel Dörfler const uint32 kMsgToggleLegend = 'tglg';
9918d3e65eSAxel Dörfler 
10018d3e65eSAxel Dörfler extern const char* kSignature;
10118d3e65eSAxel Dörfler 
10218d3e65eSAxel Dörfler 
10351591198SAxel Dörfler Scale::Scale(scale_type type)
10451591198SAxel Dörfler 	:
10551591198SAxel Dörfler 	fType(type),
10651591198SAxel Dörfler 	fMinimumValue(0),
10751591198SAxel Dörfler 	fMaximumValue(0),
10851591198SAxel Dörfler 	fInitialized(false)
10951591198SAxel Dörfler {
11051591198SAxel Dörfler }
11151591198SAxel Dörfler 
11251591198SAxel Dörfler 
11351591198SAxel Dörfler void
11451591198SAxel Dörfler Scale::Update(int64 value)
11551591198SAxel Dörfler {
11651591198SAxel Dörfler 	if (!fInitialized || fMinimumValue > value)
11751591198SAxel Dörfler 		fMinimumValue = value;
118*230e3259SAxel Dörfler 	if (!fInitialized || fMaximumValue < value)
11951591198SAxel Dörfler 		fMaximumValue = value;
12051591198SAxel Dörfler 
12151591198SAxel Dörfler 	fInitialized = true;
12251591198SAxel Dörfler }
12351591198SAxel Dörfler 
12451591198SAxel Dörfler 
12551591198SAxel Dörfler //	#pragma mark -
12651591198SAxel Dörfler 
12751591198SAxel Dörfler 
12818d3e65eSAxel Dörfler DataHistory::DataHistory(bigtime_t memorize, bigtime_t interval)
12918d3e65eSAxel Dörfler 	:
13018d3e65eSAxel Dörfler 	fBuffer(10000),
13118d3e65eSAxel Dörfler 	fMinimumValue(0),
13218d3e65eSAxel Dörfler 	fMaximumValue(0),
13318d3e65eSAxel Dörfler 	fRefreshInterval(interval),
13451591198SAxel Dörfler 	fLastIndex(-1),
13551591198SAxel Dörfler 	fScale(NULL)
13618d3e65eSAxel Dörfler {
13718d3e65eSAxel Dörfler }
13818d3e65eSAxel Dörfler 
13918d3e65eSAxel Dörfler 
14018d3e65eSAxel Dörfler DataHistory::~DataHistory()
14118d3e65eSAxel Dörfler {
14218d3e65eSAxel Dörfler }
14318d3e65eSAxel Dörfler 
14418d3e65eSAxel Dörfler 
14518d3e65eSAxel Dörfler void
14618d3e65eSAxel Dörfler DataHistory::AddValue(bigtime_t time, int64 value)
14718d3e65eSAxel Dörfler {
14818d3e65eSAxel Dörfler 	if (fBuffer.IsEmpty() || fMaximumValue < value)
14918d3e65eSAxel Dörfler 		fMaximumValue = value;
15018d3e65eSAxel Dörfler 	if (fBuffer.IsEmpty() || fMinimumValue > value)
15118d3e65eSAxel Dörfler 		fMinimumValue = value;
15251591198SAxel Dörfler 	if (fScale != NULL)
15351591198SAxel Dörfler 		fScale->Update(value);
15418d3e65eSAxel Dörfler 
15518d3e65eSAxel Dörfler 	data_item item = {time, value};
15618d3e65eSAxel Dörfler 	fBuffer.AddItem(item);
15718d3e65eSAxel Dörfler }
15818d3e65eSAxel Dörfler 
15918d3e65eSAxel Dörfler 
16018d3e65eSAxel Dörfler int64
16118d3e65eSAxel Dörfler DataHistory::ValueAt(bigtime_t time)
16218d3e65eSAxel Dörfler {
16351591198SAxel Dörfler 	int32 left = 0;
16451591198SAxel Dörfler 	int32 right = fBuffer.CountItems() - 1;
16551591198SAxel Dörfler 	data_item* item = NULL;
16651591198SAxel Dörfler 
16751591198SAxel Dörfler 	while (left <= right) {
16851591198SAxel Dörfler 		int32 index = (left + right) / 2;
16951591198SAxel Dörfler 		item = fBuffer.ItemAt(index);
17051591198SAxel Dörfler 
17151591198SAxel Dörfler 		if (item->time > time) {
17251591198SAxel Dörfler 			// search in left part
17351591198SAxel Dörfler 			right = index - 1;
17451591198SAxel Dörfler 		} else {
17584e23a5dSAxel Dörfler 			data_item* nextItem = fBuffer.ItemAt(index + 1);
17684e23a5dSAxel Dörfler 			if (nextItem == NULL)
17784e23a5dSAxel Dörfler 				return item->value;
17884e23a5dSAxel Dörfler 			if (nextItem->time > time) {
17951591198SAxel Dörfler 				// found item
18084e23a5dSAxel Dörfler 				int64 value = item->value;
18184e23a5dSAxel Dörfler 				value += int64(double(nextItem->value - value)
18284e23a5dSAxel Dörfler 					/ (nextItem->time - item->time) * (time - item->time));
18318d3e65eSAxel Dörfler 				return item->value;
18451591198SAxel Dörfler 			}
18551591198SAxel Dörfler 
18651591198SAxel Dörfler 			// search in right part
18751591198SAxel Dörfler 			left = index + 1;
18851591198SAxel Dörfler 		}
18951591198SAxel Dörfler 	}
19018d3e65eSAxel Dörfler 
19118d3e65eSAxel Dörfler 	return 0;
19218d3e65eSAxel Dörfler }
19318d3e65eSAxel Dörfler 
19418d3e65eSAxel Dörfler 
19518d3e65eSAxel Dörfler int64
19618d3e65eSAxel Dörfler DataHistory::MaximumValue() const
19718d3e65eSAxel Dörfler {
19851591198SAxel Dörfler 	if (fScale != NULL)
19951591198SAxel Dörfler 		return fScale->MaximumValue();
20051591198SAxel Dörfler 
20118d3e65eSAxel Dörfler 	return fMaximumValue;
20218d3e65eSAxel Dörfler }
20318d3e65eSAxel Dörfler 
20418d3e65eSAxel Dörfler 
20518d3e65eSAxel Dörfler int64
20618d3e65eSAxel Dörfler DataHistory::MinimumValue() const
20718d3e65eSAxel Dörfler {
20851591198SAxel Dörfler 	if (fScale != NULL)
20951591198SAxel Dörfler 		return fScale->MinimumValue();
21051591198SAxel Dörfler 
21118d3e65eSAxel Dörfler 	return fMinimumValue;
21218d3e65eSAxel Dörfler }
21318d3e65eSAxel Dörfler 
21418d3e65eSAxel Dörfler 
21518d3e65eSAxel Dörfler bigtime_t
21618d3e65eSAxel Dörfler DataHistory::Start() const
21718d3e65eSAxel Dörfler {
21818d3e65eSAxel Dörfler 	if (fBuffer.CountItems() == 0)
21918d3e65eSAxel Dörfler 		return 0;
22018d3e65eSAxel Dörfler 
22118d3e65eSAxel Dörfler 	return fBuffer.ItemAt(0)->time;
22218d3e65eSAxel Dörfler }
22318d3e65eSAxel Dörfler 
22418d3e65eSAxel Dörfler 
22518d3e65eSAxel Dörfler bigtime_t
22618d3e65eSAxel Dörfler DataHistory::End() const
22718d3e65eSAxel Dörfler {
22818d3e65eSAxel Dörfler 	if (fBuffer.CountItems() == 0)
22918d3e65eSAxel Dörfler 		return 0;
23018d3e65eSAxel Dörfler 
23118d3e65eSAxel Dörfler 	return fBuffer.ItemAt(fBuffer.CountItems() - 1)->time;
23218d3e65eSAxel Dörfler }
23318d3e65eSAxel Dörfler 
23418d3e65eSAxel Dörfler 
23518d3e65eSAxel Dörfler void
23618d3e65eSAxel Dörfler DataHistory::SetRefreshInterval(bigtime_t interval)
23718d3e65eSAxel Dörfler {
23818d3e65eSAxel Dörfler 	// TODO: adjust buffer size
23918d3e65eSAxel Dörfler }
24018d3e65eSAxel Dörfler 
24118d3e65eSAxel Dörfler 
24251591198SAxel Dörfler void
24351591198SAxel Dörfler DataHistory::SetScale(Scale* scale)
24451591198SAxel Dörfler {
24551591198SAxel Dörfler 	fScale = scale;
24651591198SAxel Dörfler }
24751591198SAxel Dörfler 
24851591198SAxel Dörfler 
24918d3e65eSAxel Dörfler //	#pragma mark -
25018d3e65eSAxel Dörfler 
25118d3e65eSAxel Dörfler 
252dc1ffc79SFrançois Revol #ifdef __HAIKU__
253065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::HistoryLayoutItem(ActivityView* parent)
254065e8de0SAxel Dörfler 	:
255065e8de0SAxel Dörfler 	fParent(parent),
256065e8de0SAxel Dörfler 	fFrame()
257065e8de0SAxel Dörfler {
258065e8de0SAxel Dörfler }
259065e8de0SAxel Dörfler 
260065e8de0SAxel Dörfler 
261065e8de0SAxel Dörfler bool
262065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::IsVisible()
263065e8de0SAxel Dörfler {
264065e8de0SAxel Dörfler 	return !fParent->IsHidden(fParent);
265065e8de0SAxel Dörfler }
266065e8de0SAxel Dörfler 
267065e8de0SAxel Dörfler 
268065e8de0SAxel Dörfler void
269065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::SetVisible(bool visible)
270065e8de0SAxel Dörfler {
271065e8de0SAxel Dörfler 	// not allowed
272065e8de0SAxel Dörfler }
273065e8de0SAxel Dörfler 
274065e8de0SAxel Dörfler 
275065e8de0SAxel Dörfler BRect
276065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::Frame()
277065e8de0SAxel Dörfler {
278065e8de0SAxel Dörfler 	return fFrame;
279065e8de0SAxel Dörfler }
280065e8de0SAxel Dörfler 
281065e8de0SAxel Dörfler 
282065e8de0SAxel Dörfler void
283065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::SetFrame(BRect frame)
284065e8de0SAxel Dörfler {
285065e8de0SAxel Dörfler 	fFrame = frame;
286065e8de0SAxel Dörfler 	fParent->_UpdateFrame();
287065e8de0SAxel Dörfler }
288065e8de0SAxel Dörfler 
289065e8de0SAxel Dörfler 
290065e8de0SAxel Dörfler BView*
291065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::View()
292065e8de0SAxel Dörfler {
293065e8de0SAxel Dörfler 	return fParent;
294065e8de0SAxel Dörfler }
295065e8de0SAxel Dörfler 
296065e8de0SAxel Dörfler 
297065e8de0SAxel Dörfler BSize
298065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::BasePreferredSize()
299065e8de0SAxel Dörfler {
300065e8de0SAxel Dörfler 	BSize size(BaseMaxSize());
301065e8de0SAxel Dörfler 	return size;
302065e8de0SAxel Dörfler }
303065e8de0SAxel Dörfler 
304065e8de0SAxel Dörfler 
305065e8de0SAxel Dörfler //	#pragma mark -
306065e8de0SAxel Dörfler 
307065e8de0SAxel Dörfler 
308065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::LegendLayoutItem(ActivityView* parent)
309065e8de0SAxel Dörfler 	:
310065e8de0SAxel Dörfler 	fParent(parent),
311065e8de0SAxel Dörfler 	fFrame()
312065e8de0SAxel Dörfler {
313065e8de0SAxel Dörfler }
314065e8de0SAxel Dörfler 
315065e8de0SAxel Dörfler 
316065e8de0SAxel Dörfler bool
317065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::IsVisible()
318065e8de0SAxel Dörfler {
319065e8de0SAxel Dörfler 	return !fParent->IsHidden(fParent);
320065e8de0SAxel Dörfler }
321065e8de0SAxel Dörfler 
322065e8de0SAxel Dörfler 
323065e8de0SAxel Dörfler void
324065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::SetVisible(bool visible)
325065e8de0SAxel Dörfler {
326065e8de0SAxel Dörfler 	// not allowed
327065e8de0SAxel Dörfler }
328065e8de0SAxel Dörfler 
329065e8de0SAxel Dörfler 
330065e8de0SAxel Dörfler BRect
331065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::Frame()
332065e8de0SAxel Dörfler {
333065e8de0SAxel Dörfler 	return fFrame;
334065e8de0SAxel Dörfler }
335065e8de0SAxel Dörfler 
336065e8de0SAxel Dörfler 
337065e8de0SAxel Dörfler void
338065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::SetFrame(BRect frame)
339065e8de0SAxel Dörfler {
340065e8de0SAxel Dörfler 	fFrame = frame;
341065e8de0SAxel Dörfler 	fParent->_UpdateFrame();
342065e8de0SAxel Dörfler }
343065e8de0SAxel Dörfler 
344065e8de0SAxel Dörfler 
345065e8de0SAxel Dörfler BView*
346065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::View()
347065e8de0SAxel Dörfler {
348065e8de0SAxel Dörfler 	return fParent;
349065e8de0SAxel Dörfler }
350065e8de0SAxel Dörfler 
351065e8de0SAxel Dörfler 
352065e8de0SAxel Dörfler BSize
353065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::BaseMinSize()
354065e8de0SAxel Dörfler {
355065e8de0SAxel Dörfler 	// TODO: Cache the info. Might be too expensive for this call.
356065e8de0SAxel Dörfler 	BSize size;
357065e8de0SAxel Dörfler 	size.width = 80;
358065e8de0SAxel Dörfler 	size.height = fParent->_LegendHeight();
359065e8de0SAxel Dörfler 
360065e8de0SAxel Dörfler 	return size;
361065e8de0SAxel Dörfler }
362065e8de0SAxel Dörfler 
363065e8de0SAxel Dörfler 
364065e8de0SAxel Dörfler BSize
365065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::BaseMaxSize()
366065e8de0SAxel Dörfler {
367065e8de0SAxel Dörfler 	BSize size(BaseMinSize());
368065e8de0SAxel Dörfler 	size.width = B_SIZE_UNLIMITED;
369065e8de0SAxel Dörfler 	return size;
370065e8de0SAxel Dörfler }
371065e8de0SAxel Dörfler 
372065e8de0SAxel Dörfler 
373065e8de0SAxel Dörfler BSize
374065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::BasePreferredSize()
375065e8de0SAxel Dörfler {
376065e8de0SAxel Dörfler 	BSize size(BaseMinSize());
377065e8de0SAxel Dörfler 	return size;
378065e8de0SAxel Dörfler }
379065e8de0SAxel Dörfler 
380065e8de0SAxel Dörfler 
381065e8de0SAxel Dörfler BAlignment
382065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::BaseAlignment()
383065e8de0SAxel Dörfler {
384065e8de0SAxel Dörfler 	return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
385065e8de0SAxel Dörfler }
386dc1ffc79SFrançois Revol #endif
387065e8de0SAxel Dörfler 
388065e8de0SAxel Dörfler 
389065e8de0SAxel Dörfler //	#pragma mark -
390065e8de0SAxel Dörfler 
391065e8de0SAxel Dörfler 
39218d3e65eSAxel Dörfler ActivityView::ActivityView(BRect frame, const char* name,
3933a4a2141SAxel Dörfler 		const BMessage* settings, uint32 resizingMode)
39418d3e65eSAxel Dörfler 	: BView(frame, name, resizingMode,
395d4216445SAxel Dörfler 		B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS),
396d4216445SAxel Dörfler 	fSourcesLock("data sources")
39718d3e65eSAxel Dörfler {
3983a4a2141SAxel Dörfler 	_Init(settings);
3993a4a2141SAxel Dörfler 
4003a4a2141SAxel Dörfler 	BRect rect(Bounds());
4013a4a2141SAxel Dörfler 	rect.top = rect.bottom - 7;
4023a4a2141SAxel Dörfler 	rect.left = rect.right - 7;
4033a4a2141SAxel Dörfler 	BDragger* dragger = new BDragger(rect, this,
4043a4a2141SAxel Dörfler 		B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
4053a4a2141SAxel Dörfler 	AddChild(dragger);
4063a4a2141SAxel Dörfler }
4073a4a2141SAxel Dörfler 
4083a4a2141SAxel Dörfler 
4093a4a2141SAxel Dörfler ActivityView::ActivityView(const char* name, const BMessage* settings)
410cbd4bc95SFrançois Revol #ifdef __HAIKU__
411d4216445SAxel Dörfler 	: BView(name, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS),
412cbd4bc95SFrançois Revol #else
413d4216445SAxel Dörfler 	: BView(BRect(0,0,300,200), name, B_FOLLOW_NONE,
414d4216445SAxel Dörfler 		B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS),
415cbd4bc95SFrançois Revol #endif
416d4216445SAxel Dörfler 	fSourcesLock("data sources")
4173a4a2141SAxel Dörfler {
41879cbd226SFrançois Revol 	SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
4199c89c450SAxel Dörfler 
4203a4a2141SAxel Dörfler 	_Init(settings);
42118d3e65eSAxel Dörfler 
42218d3e65eSAxel Dörfler 	BRect rect(Bounds());
42318d3e65eSAxel Dörfler 	rect.top = rect.bottom - 7;
42418d3e65eSAxel Dörfler 	rect.left = rect.right - 7;
42518d3e65eSAxel Dörfler 	BDragger* dragger = new BDragger(rect, this,
42618d3e65eSAxel Dörfler 		B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
42718d3e65eSAxel Dörfler 	AddChild(dragger);
42818d3e65eSAxel Dörfler }
42918d3e65eSAxel Dörfler 
43018d3e65eSAxel Dörfler 
43118d3e65eSAxel Dörfler ActivityView::ActivityView(BMessage* archive)
43218d3e65eSAxel Dörfler 	: BView(archive)
43318d3e65eSAxel Dörfler {
43418d3e65eSAxel Dörfler 	_Init(archive);
43518d3e65eSAxel Dörfler }
43618d3e65eSAxel Dörfler 
43718d3e65eSAxel Dörfler 
43818d3e65eSAxel Dörfler ActivityView::~ActivityView()
43918d3e65eSAxel Dörfler {
4403a4a2141SAxel Dörfler 	delete fOffscreen;
44174158bb4SFrançois Revol 	delete fSystemInfoHandler;
44218d3e65eSAxel Dörfler }
44318d3e65eSAxel Dörfler 
44418d3e65eSAxel Dörfler 
44518d3e65eSAxel Dörfler void
44618d3e65eSAxel Dörfler ActivityView::_Init(const BMessage* settings)
44718d3e65eSAxel Dörfler {
4489c89c450SAxel Dörfler 	fHistoryBackgroundColor = (rgb_color){255, 255, 240};
4499c89c450SAxel Dörfler 	fLegendBackgroundColor = LowColor();
4509c89c450SAxel Dörfler 		// the low color is restored by the BView unarchiving
4513a4a2141SAxel Dörfler 	fOffscreen = NULL;
452dc1ffc79SFrançois Revol #ifdef __HAIKU__
453065e8de0SAxel Dörfler 	fHistoryLayoutItem = NULL;
454065e8de0SAxel Dörfler 	fLegendLayoutItem = NULL;
455dc1ffc79SFrançois Revol #endif
4563a4a2141SAxel Dörfler 	SetViewColor(B_TRANSPARENT_COLOR);
45718d3e65eSAxel Dörfler 
45818d3e65eSAxel Dörfler 	fRefreshInterval = kInitialRefreshInterval;
45918d3e65eSAxel Dörfler 	fDrawInterval = kInitialRefreshInterval * 2;
46018d3e65eSAxel Dörfler 	fLastRefresh = 0;
46118d3e65eSAxel Dörfler 	fDrawResolution = 1;
46251591198SAxel Dörfler 	fZooming = false;
46318d3e65eSAxel Dörfler 
46474158bb4SFrançois Revol 	fSystemInfoHandler = new SystemInfoHandler;
46574158bb4SFrançois Revol 
4663a4a2141SAxel Dörfler 	if (settings == NULL
4673a4a2141SAxel Dörfler 		|| settings->FindBool("show legend", &fShowLegend) != B_OK)
4683a4a2141SAxel Dörfler 		fShowLegend = true;
4693a4a2141SAxel Dörfler 
47051591198SAxel Dörfler 	if (settings == NULL)
4713a4a2141SAxel Dörfler 		return;
4723a4a2141SAxel Dörfler 
4739c89c450SAxel Dörfler 	ssize_t colorLength;
47479cbd226SFrançois Revol 	rgb_color *color;
4759c89c450SAxel Dörfler 	if (settings->FindData("history background color", B_RGB_COLOR_TYPE,
4769c89c450SAxel Dörfler 			(const void **)&color, &colorLength) == B_OK
4779c89c450SAxel Dörfler 		&& colorLength == sizeof(rgb_color))
4789c89c450SAxel Dörfler 		fHistoryBackgroundColor = *color;
47979cbd226SFrançois Revol 
4803a4a2141SAxel Dörfler 	const char* name;
4813a4a2141SAxel Dörfler 	for (int32 i = 0; settings->FindString("source", i, &name) == B_OK; i++) {
4821201d52eSAxel Dörfler 		AddDataSource(DataSource::FindSource(name), settings);
4833a4a2141SAxel Dörfler 	}
48418d3e65eSAxel Dörfler }
48518d3e65eSAxel Dörfler 
48618d3e65eSAxel Dörfler 
48718d3e65eSAxel Dörfler status_t
48818d3e65eSAxel Dörfler ActivityView::Archive(BMessage* into, bool deep) const
48918d3e65eSAxel Dörfler {
49018d3e65eSAxel Dörfler 	status_t status;
49118d3e65eSAxel Dörfler 
49218d3e65eSAxel Dörfler 	status = BView::Archive(into, deep);
49318d3e65eSAxel Dörfler 	if (status < B_OK)
49418d3e65eSAxel Dörfler 		return status;
49518d3e65eSAxel Dörfler 
49618d3e65eSAxel Dörfler 	status = into->AddString("add_on", kSignature);
49718d3e65eSAxel Dörfler 	if (status < B_OK)
49818d3e65eSAxel Dörfler 		return status;
49918d3e65eSAxel Dörfler 
50018d3e65eSAxel Dörfler 	status = SaveState(*into);
50118d3e65eSAxel Dörfler 	if (status < B_OK)
50218d3e65eSAxel Dörfler 		return status;
50318d3e65eSAxel Dörfler 
50418d3e65eSAxel Dörfler 	return B_OK;
50518d3e65eSAxel Dörfler }
50618d3e65eSAxel Dörfler 
50718d3e65eSAxel Dörfler 
50818d3e65eSAxel Dörfler BArchivable*
50918d3e65eSAxel Dörfler ActivityView::Instantiate(BMessage* archive)
51018d3e65eSAxel Dörfler {
51118d3e65eSAxel Dörfler 	if (!validate_instantiation(archive, "ActivityView"))
51218d3e65eSAxel Dörfler 		return NULL;
51318d3e65eSAxel Dörfler 
51418d3e65eSAxel Dörfler 	return new ActivityView(archive);
51518d3e65eSAxel Dörfler }
51618d3e65eSAxel Dörfler 
51718d3e65eSAxel Dörfler 
51818d3e65eSAxel Dörfler status_t
51918d3e65eSAxel Dörfler ActivityView::SaveState(BMessage& state) const
52018d3e65eSAxel Dörfler {
5213a4a2141SAxel Dörfler 	status_t status = state.AddBool("show legend", fShowLegend);
5223a4a2141SAxel Dörfler 	if (status != B_OK)
5233a4a2141SAxel Dörfler 		return status;
5243a4a2141SAxel Dörfler 
5259c89c450SAxel Dörfler 	status = state.AddData("history background color", B_RGB_COLOR_TYPE,
5269c89c450SAxel Dörfler 		&fHistoryBackgroundColor, sizeof(rgb_color));
52779cbd226SFrançois Revol 	if (status != B_OK)
52879cbd226SFrançois Revol 		return status;
52979cbd226SFrançois Revol 
5303a4a2141SAxel Dörfler 	for (int32 i = 0; i < fSources.CountItems(); i++) {
5313a4a2141SAxel Dörfler 		DataSource* source = fSources.ItemAt(i);
5323a4a2141SAxel Dörfler 
5333a4a2141SAxel Dörfler 		if (!source->PerCPU() || source->CPU() == 0)
5343a4a2141SAxel Dörfler 			status = state.AddString("source", source->Name());
5353a4a2141SAxel Dörfler 		if (status != B_OK)
5363a4a2141SAxel Dörfler 			return status;
5373a4a2141SAxel Dörfler 
5389c89c450SAxel Dörfler 		BString name = source->Name();
5399c89c450SAxel Dörfler 		name << " color";
5409c89c450SAxel Dörfler 		rgb_color color = source->Color();
5419c89c450SAxel Dörfler 		state.AddData(name.String(), B_RGB_COLOR_TYPE, &color,
5429c89c450SAxel Dörfler 			sizeof(rgb_color));
5433a4a2141SAxel Dörfler 	}
5443a4a2141SAxel Dörfler 	return B_OK;
54518d3e65eSAxel Dörfler }
54618d3e65eSAxel Dörfler 
54718d3e65eSAxel Dörfler 
54851591198SAxel Dörfler Scale*
54951591198SAxel Dörfler ActivityView::_ScaleFor(scale_type type)
55051591198SAxel Dörfler {
55151591198SAxel Dörfler 	if (type == kNoScale)
55251591198SAxel Dörfler 		return NULL;
55351591198SAxel Dörfler 
55451591198SAxel Dörfler 	std::map<scale_type, ::Scale*>::iterator iterator = fScales.find(type);
55551591198SAxel Dörfler 	if (iterator != fScales.end())
55651591198SAxel Dörfler 		return iterator->second;
55751591198SAxel Dörfler 
55851591198SAxel Dörfler 	// add new scale
55951591198SAxel Dörfler 	::Scale* scale = new ::Scale(type);
56051591198SAxel Dörfler 	fScales[type] = scale;
56151591198SAxel Dörfler 
56251591198SAxel Dörfler 	return scale;
56351591198SAxel Dörfler }
56451591198SAxel Dörfler 
56551591198SAxel Dörfler 
566dc1ffc79SFrançois Revol #ifdef __HAIKU__
567065e8de0SAxel Dörfler BLayoutItem*
568065e8de0SAxel Dörfler ActivityView::CreateHistoryLayoutItem()
569065e8de0SAxel Dörfler {
570065e8de0SAxel Dörfler 	if (fHistoryLayoutItem == NULL)
571065e8de0SAxel Dörfler 		fHistoryLayoutItem = new HistoryLayoutItem(this);
572065e8de0SAxel Dörfler 
573065e8de0SAxel Dörfler 	return fHistoryLayoutItem;
574065e8de0SAxel Dörfler }
575065e8de0SAxel Dörfler 
576065e8de0SAxel Dörfler 
577065e8de0SAxel Dörfler BLayoutItem*
578065e8de0SAxel Dörfler ActivityView::CreateLegendLayoutItem()
579065e8de0SAxel Dörfler {
580065e8de0SAxel Dörfler 	if (fLegendLayoutItem == NULL)
581065e8de0SAxel Dörfler 		fLegendLayoutItem = new LegendLayoutItem(this);
582065e8de0SAxel Dörfler 
583065e8de0SAxel Dörfler 	return fLegendLayoutItem;
584065e8de0SAxel Dörfler }
585dc1ffc79SFrançois Revol #endif
586065e8de0SAxel Dörfler 
5879c89c450SAxel Dörfler 
58818d3e65eSAxel Dörfler DataSource*
5893a4a2141SAxel Dörfler ActivityView::FindDataSource(const DataSource* search)
59018d3e65eSAxel Dörfler {
591d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
592d4216445SAxel Dörfler 
59318d3e65eSAxel Dörfler 	for (int32 i = fSources.CountItems(); i-- > 0;) {
59418d3e65eSAxel Dörfler 		DataSource* source = fSources.ItemAt(i);
5953a4a2141SAxel Dörfler 		if (!strcmp(source->Name(), search->Name()))
59618d3e65eSAxel Dörfler 			return source;
59718d3e65eSAxel Dörfler 	}
59818d3e65eSAxel Dörfler 
59918d3e65eSAxel Dörfler 	return NULL;
60018d3e65eSAxel Dörfler }
60118d3e65eSAxel Dörfler 
60218d3e65eSAxel Dörfler 
60318d3e65eSAxel Dörfler status_t
6049c89c450SAxel Dörfler ActivityView::AddDataSource(const DataSource* source, const BMessage* state)
60518d3e65eSAxel Dörfler {
6063a4a2141SAxel Dörfler 	if (source == NULL)
6073a4a2141SAxel Dörfler 		return B_BAD_VALUE;
6083a4a2141SAxel Dörfler 
609d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
610d4216445SAxel Dörfler 
6113a4a2141SAxel Dörfler 	int32 insert = DataSource::IndexOf(source);
6123a4a2141SAxel Dörfler 	for (int32 i = 0; i < fSources.CountItems() && i < insert; i++) {
6133a4a2141SAxel Dörfler 		DataSource* before = fSources.ItemAt(i);
6143a4a2141SAxel Dörfler 		if (DataSource::IndexOf(before) > insert) {
6153a4a2141SAxel Dörfler 			insert = i;
6163a4a2141SAxel Dörfler 			break;
6173a4a2141SAxel Dörfler 		}
6183a4a2141SAxel Dörfler 	}
6193a4a2141SAxel Dörfler 	if (insert > fSources.CountItems())
6203a4a2141SAxel Dörfler 		insert = fSources.CountItems();
6213a4a2141SAxel Dörfler 
6223a4a2141SAxel Dörfler 	uint32 count = 1;
6233a4a2141SAxel Dörfler 	if (source->PerCPU()) {
6243a4a2141SAxel Dörfler 		SystemInfo info;
6253a4a2141SAxel Dörfler 		count = info.CPUCount();
6263a4a2141SAxel Dörfler 	}
6273a4a2141SAxel Dörfler 
6283a4a2141SAxel Dörfler 	for (uint32 i = 0; i < count; i++) {
62918d3e65eSAxel Dörfler 		DataHistory* values = new(std::nothrow) DataHistory(10 * 60000000LL,
63018d3e65eSAxel Dörfler 			fRefreshInterval);
63118d3e65eSAxel Dörfler 		if (values == NULL)
63218d3e65eSAxel Dörfler 			return B_NO_MEMORY;
6333a4a2141SAxel Dörfler 
6343a4a2141SAxel Dörfler 		if (!fValues.AddItem(values, insert + i)) {
63518d3e65eSAxel Dörfler 			delete values;
63618d3e65eSAxel Dörfler 			return B_NO_MEMORY;
63718d3e65eSAxel Dörfler 		}
63818d3e65eSAxel Dörfler 
63951591198SAxel Dörfler 		values->SetScale(_ScaleFor(source->ScaleType()));
64051591198SAxel Dörfler 
6413a4a2141SAxel Dörfler 		DataSource* copy;
6423a4a2141SAxel Dörfler 		if (source->PerCPU())
6433a4a2141SAxel Dörfler 			copy = source->CopyForCPU(i);
6443a4a2141SAxel Dörfler 		else
6453a4a2141SAxel Dörfler 			copy = source->Copy();
6463a4a2141SAxel Dörfler 
6479c89c450SAxel Dörfler 		BString colorName = source->Name();
6489c89c450SAxel Dörfler 		colorName << " color";
6499c89c450SAxel Dörfler 		if (state != NULL) {
6509c89c450SAxel Dörfler 			const rgb_color* color = NULL;
6519c89c450SAxel Dörfler 			ssize_t colorLength;
6529c89c450SAxel Dörfler 			if (state->FindData(colorName.String(), B_RGB_COLOR_TYPE, i,
6539c89c450SAxel Dörfler 					(const void**)&color, &colorLength) == B_OK
6549c89c450SAxel Dörfler 				&& colorLength == sizeof(rgb_color))
6559c89c450SAxel Dörfler 				copy->SetColor(*color);
6569c89c450SAxel Dörfler 		}
6579c89c450SAxel Dörfler 
6583a4a2141SAxel Dörfler 		if (!fSources.AddItem(copy, insert + i)) {
65918d3e65eSAxel Dörfler 			fValues.RemoveItem(values);
66018d3e65eSAxel Dörfler 			delete values;
66118d3e65eSAxel Dörfler 			return B_NO_MEMORY;
66218d3e65eSAxel Dörfler 		}
6633a4a2141SAxel Dörfler 	}
66418d3e65eSAxel Dörfler 
665dc1ffc79SFrançois Revol #ifdef __HAIKU__
666065e8de0SAxel Dörfler 	InvalidateLayout();
667dc1ffc79SFrançois Revol #endif
66818d3e65eSAxel Dörfler 	return B_OK;
66918d3e65eSAxel Dörfler }
67018d3e65eSAxel Dörfler 
67118d3e65eSAxel Dörfler 
67218d3e65eSAxel Dörfler status_t
6733a4a2141SAxel Dörfler ActivityView::RemoveDataSource(const DataSource* remove)
67418d3e65eSAxel Dörfler {
675065e8de0SAxel Dörfler 	bool removed = false;
676065e8de0SAxel Dörfler 
677d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
678d4216445SAxel Dörfler 
6793a4a2141SAxel Dörfler 	while (true) {
6803a4a2141SAxel Dörfler 		DataSource* source = FindDataSource(remove);
6819c89c450SAxel Dörfler debug_printf("SEARCH %s, found %p\n", remove->Name(), source);
682065e8de0SAxel Dörfler 		if (source == NULL) {
683065e8de0SAxel Dörfler 			if (removed)
684065e8de0SAxel Dörfler 				break;
685065e8de0SAxel Dörfler 			return B_ENTRY_NOT_FOUND;
686065e8de0SAxel Dörfler 		}
6873a4a2141SAxel Dörfler 
68818d3e65eSAxel Dörfler 		int32 index = fSources.IndexOf(source);
68918d3e65eSAxel Dörfler 		if (index < 0)
69018d3e65eSAxel Dörfler 			return B_ENTRY_NOT_FOUND;
69118d3e65eSAxel Dörfler 
69218d3e65eSAxel Dörfler 		fSources.RemoveItemAt(index);
69318d3e65eSAxel Dörfler 		delete source;
69418d3e65eSAxel Dörfler 		DataHistory* values = fValues.RemoveItemAt(index);
69518d3e65eSAxel Dörfler 		delete values;
696065e8de0SAxel Dörfler 		removed = true;
6973a4a2141SAxel Dörfler 	}
69818d3e65eSAxel Dörfler 
699dc1ffc79SFrançois Revol #ifdef __HAIKU__
700065e8de0SAxel Dörfler 	InvalidateLayout();
701dc1ffc79SFrançois Revol #endif
70218d3e65eSAxel Dörfler 	return B_OK;
70318d3e65eSAxel Dörfler }
70418d3e65eSAxel Dörfler 
70518d3e65eSAxel Dörfler 
70618d3e65eSAxel Dörfler void
70718d3e65eSAxel Dörfler ActivityView::RemoveAllDataSources()
70818d3e65eSAxel Dörfler {
709d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
710d4216445SAxel Dörfler 
71118d3e65eSAxel Dörfler 	fSources.MakeEmpty();
71218d3e65eSAxel Dörfler 	fValues.MakeEmpty();
71318d3e65eSAxel Dörfler }
71418d3e65eSAxel Dörfler 
71518d3e65eSAxel Dörfler 
71618d3e65eSAxel Dörfler void
71718d3e65eSAxel Dörfler ActivityView::AttachedToWindow()
71818d3e65eSAxel Dörfler {
71974158bb4SFrançois Revol 	Looper()->AddHandler(fSystemInfoHandler);
7206f6ba875SAxel Dörfler 	fSystemInfoHandler->StartWatching();
7216f6ba875SAxel Dörfler 
722d4216445SAxel Dörfler 	fRefreshSem = create_sem(0, "refresh sem");
723d4216445SAxel Dörfler 	fRefreshThread = spawn_thread(&_RefreshThread, "source refresh",
724d4216445SAxel Dörfler 		B_NORMAL_PRIORITY, this);
725d4216445SAxel Dörfler 	resume_thread(fRefreshThread);
7263a4a2141SAxel Dörfler 
7273a4a2141SAxel Dörfler 	FrameResized(Bounds().Width(), Bounds().Height());
72818d3e65eSAxel Dörfler }
72918d3e65eSAxel Dörfler 
73018d3e65eSAxel Dörfler 
73118d3e65eSAxel Dörfler void
73218d3e65eSAxel Dörfler ActivityView::DetachedFromWindow()
73318d3e65eSAxel Dörfler {
7346f6ba875SAxel Dörfler 	fSystemInfoHandler->StopWatching();
73574158bb4SFrançois Revol 	Looper()->RemoveHandler(fSystemInfoHandler);
7366f6ba875SAxel Dörfler 
737d4216445SAxel Dörfler 	delete_sem(fRefreshSem);
738d4216445SAxel Dörfler 	wait_for_thread(fRefreshThread, NULL);
73918d3e65eSAxel Dörfler }
74018d3e65eSAxel Dörfler 
74118d3e65eSAxel Dörfler 
742cbd4bc95SFrançois Revol #ifdef __HAIKU__
7433a4a2141SAxel Dörfler BSize
7443a4a2141SAxel Dörfler ActivityView::MinSize()
7453a4a2141SAxel Dörfler {
7463a4a2141SAxel Dörfler 	BSize size(32, 32);
7473a4a2141SAxel Dörfler 	if (fShowLegend)
7489c89c450SAxel Dörfler 		size.height = _LegendHeight();
7493a4a2141SAxel Dörfler 
7503a4a2141SAxel Dörfler 	return size;
7513a4a2141SAxel Dörfler }
752cbd4bc95SFrançois Revol #endif
7533a4a2141SAxel Dörfler 
7543a4a2141SAxel Dörfler 
75518d3e65eSAxel Dörfler void
75618d3e65eSAxel Dörfler ActivityView::FrameResized(float /*width*/, float /*height*/)
75718d3e65eSAxel Dörfler {
7583a4a2141SAxel Dörfler 	_UpdateOffscreenBitmap();
7593a4a2141SAxel Dörfler }
7603a4a2141SAxel Dörfler 
7613a4a2141SAxel Dörfler 
7623a4a2141SAxel Dörfler void
7639c89c450SAxel Dörfler ActivityView::_UpdateOffscreenBitmap()
7643a4a2141SAxel Dörfler {
7653a4a2141SAxel Dörfler 	BRect frame = _HistoryFrame();
7669c89c450SAxel Dörfler 	if (fOffscreen != NULL && frame == fOffscreen->Bounds())
7673a4a2141SAxel Dörfler 		return;
7683a4a2141SAxel Dörfler 
7693a4a2141SAxel Dörfler 	delete fOffscreen;
7703a4a2141SAxel Dörfler 
7713a4a2141SAxel Dörfler 	// create offscreen bitmap
7723a4a2141SAxel Dörfler 
7733a4a2141SAxel Dörfler 	fOffscreen = new(std::nothrow) BBitmap(frame, B_BITMAP_ACCEPTS_VIEWS,
7743a4a2141SAxel Dörfler 		B_RGB32);
7753a4a2141SAxel Dörfler 	if (fOffscreen == NULL || fOffscreen->InitCheck() != B_OK) {
7763a4a2141SAxel Dörfler 		delete fOffscreen;
7773a4a2141SAxel Dörfler 		fOffscreen = NULL;
7783a4a2141SAxel Dörfler 		return;
7793a4a2141SAxel Dörfler 	}
7803a4a2141SAxel Dörfler 
7813a4a2141SAxel Dörfler 	BView* view = new BView(frame, NULL, B_FOLLOW_NONE, B_SUBPIXEL_PRECISE);
7829c89c450SAxel Dörfler 	view->SetViewColor(fHistoryBackgroundColor);
7833a4a2141SAxel Dörfler 	view->SetLowColor(view->ViewColor());
7843a4a2141SAxel Dörfler 	fOffscreen->AddChild(view);
78518d3e65eSAxel Dörfler }
78618d3e65eSAxel Dörfler 
78718d3e65eSAxel Dörfler 
7889c89c450SAxel Dörfler BView*
7899c89c450SAxel Dörfler ActivityView::_OffscreenView()
7909c89c450SAxel Dörfler {
7919c89c450SAxel Dörfler 	if (fOffscreen == NULL)
7929c89c450SAxel Dörfler 		return NULL;
7939c89c450SAxel Dörfler 
7949c89c450SAxel Dörfler 	return fOffscreen->ChildAt(0);
7959c89c450SAxel Dörfler }
7969c89c450SAxel Dörfler 
7979c89c450SAxel Dörfler 
79818d3e65eSAxel Dörfler void
79918d3e65eSAxel Dörfler ActivityView::MouseDown(BPoint where)
80018d3e65eSAxel Dörfler {
80151591198SAxel Dörfler 	int32 buttons = B_SECONDARY_MOUSE_BUTTON;
80251591198SAxel Dörfler 	if (Looper() != NULL && Looper()->CurrentMessage() != NULL)
80318d3e65eSAxel Dörfler 		Looper()->CurrentMessage()->FindInt32("buttons", &buttons);
80451591198SAxel Dörfler 
80551591198SAxel Dörfler 	if (buttons == B_PRIMARY_MOUSE_BUTTON) {
80651591198SAxel Dörfler 		fZoomPoint = where;
80751591198SAxel Dörfler 		fOriginalResolution = fDrawResolution;
80851591198SAxel Dörfler 		fZooming = true;
80951591198SAxel Dörfler 		return;
81018d3e65eSAxel Dörfler 	}
81118d3e65eSAxel Dörfler 
81218d3e65eSAxel Dörfler 	BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING, false, false);
81318d3e65eSAxel Dörfler 	menu->SetFont(be_plain_font);
8143a4a2141SAxel Dörfler 
81543eda1cdSAxel Dörfler 	BMenu* additionalMenu = new BMenu("Additional Items");
816dc1ffc79SFrançois Revol 	additionalMenu->SetFont(be_plain_font);
817dc1ffc79SFrançois Revol 
8183a4a2141SAxel Dörfler 	SystemInfo info;
81918d3e65eSAxel Dörfler 	BMenuItem* item;
82018d3e65eSAxel Dörfler 
82118d3e65eSAxel Dörfler 	for (int32 i = 0; i < DataSource::CountSources(); i++) {
82218d3e65eSAxel Dörfler 		const DataSource* source = DataSource::SourceAt(i);
82318d3e65eSAxel Dörfler 
8243a4a2141SAxel Dörfler 		if (source->MultiCPUOnly() && info.CPUCount() == 1)
8253a4a2141SAxel Dörfler 			continue;
8263a4a2141SAxel Dörfler 
82718d3e65eSAxel Dörfler 		BMessage* message = new BMessage(kMsgToggleDataSource);
82818d3e65eSAxel Dörfler 		message->AddInt32("index", i);
82918d3e65eSAxel Dörfler 
8303a4a2141SAxel Dörfler 		item = new BMenuItem(source->Name(), message);
8313a4a2141SAxel Dörfler 		if (FindDataSource(source))
83218d3e65eSAxel Dörfler 			item->SetMarked(true);
83318d3e65eSAxel Dörfler 
83443eda1cdSAxel Dörfler 		if (source->Primary())
83518d3e65eSAxel Dörfler 			menu->AddItem(item);
83643eda1cdSAxel Dörfler 		else
83743eda1cdSAxel Dörfler 			additionalMenu->AddItem(item);
83818d3e65eSAxel Dörfler 	}
83918d3e65eSAxel Dörfler 
84043eda1cdSAxel Dörfler 	menu->AddItem(new BMenuItem(additionalMenu));
8413a4a2141SAxel Dörfler 	menu->AddSeparatorItem();
8423a4a2141SAxel Dörfler 	menu->AddItem(new BMenuItem(fShowLegend ? "Hide Legend" : "Show Legend",
8433a4a2141SAxel Dörfler 		new BMessage(kMsgToggleLegend)));
8443a4a2141SAxel Dörfler 
84518d3e65eSAxel Dörfler 	menu->SetTargetForItems(this);
846dc1ffc79SFrançois Revol 	additionalMenu->SetTargetForItems(this);
84718d3e65eSAxel Dörfler 
8483f315b26SAxel Dörfler 	ActivityWindow* window = dynamic_cast<ActivityWindow*>(Window());
8493f315b26SAxel Dörfler 	if (window != NULL && window->ActivityViewCount() > 1) {
8503f315b26SAxel Dörfler 		menu->AddSeparatorItem();
8513f315b26SAxel Dörfler 		BMessage* message = new BMessage(kMsgRemoveView);
8523f315b26SAxel Dörfler 		message->AddPointer("view", this);
8533f315b26SAxel Dörfler 		menu->AddItem(item = new BMenuItem("Remove View", message));
8543f315b26SAxel Dörfler 		item->SetTarget(window);
8553f315b26SAxel Dörfler 	}
8563f315b26SAxel Dörfler 
85718d3e65eSAxel Dörfler 	ConvertToScreen(&where);
85818d3e65eSAxel Dörfler 	menu->Go(where, true, false, true);
85918d3e65eSAxel Dörfler 
86018d3e65eSAxel Dörfler }
86118d3e65eSAxel Dörfler 
86218d3e65eSAxel Dörfler 
86318d3e65eSAxel Dörfler void
86451591198SAxel Dörfler ActivityView::MouseUp(BPoint where)
86551591198SAxel Dörfler {
86651591198SAxel Dörfler 	fZooming = false;
86751591198SAxel Dörfler }
86851591198SAxel Dörfler 
86951591198SAxel Dörfler 
87051591198SAxel Dörfler void
87118d3e65eSAxel Dörfler ActivityView::MouseMoved(BPoint where, uint32 transit,
87218d3e65eSAxel Dörfler 	const BMessage* dragMessage)
87318d3e65eSAxel Dörfler {
87451591198SAxel Dörfler 	if (!fZooming)
87551591198SAxel Dörfler 		return;
87651591198SAxel Dörfler 
87751591198SAxel Dörfler 	int32 previousResolution = fDrawResolution;
87851591198SAxel Dörfler 
87951591198SAxel Dörfler 	int32 shift = int32(where.x - fZoomPoint.x) / 25;
88051591198SAxel Dörfler 	if (shift > 0)
88151591198SAxel Dörfler 		fDrawResolution = fOriginalResolution << shift;
88251591198SAxel Dörfler 	else
88351591198SAxel Dörfler 		fDrawResolution = fOriginalResolution >> -shift;
88451591198SAxel Dörfler 
88551591198SAxel Dörfler 	if (fDrawResolution < 1)
88651591198SAxel Dörfler 		fDrawResolution = 1;
88751591198SAxel Dörfler 	if (fDrawResolution > 128)
88851591198SAxel Dörfler 		fDrawResolution = 128;
88951591198SAxel Dörfler 
89051591198SAxel Dörfler 	if (previousResolution != fDrawResolution)
89151591198SAxel Dörfler 		Invalidate();
89218d3e65eSAxel Dörfler }
89318d3e65eSAxel Dörfler 
89418d3e65eSAxel Dörfler 
89518d3e65eSAxel Dörfler void
89618d3e65eSAxel Dörfler ActivityView::MessageReceived(BMessage* message)
89718d3e65eSAxel Dörfler {
898c28f8ea3SFrançois Revol 	// if a color is dropped, use it as background
899c28f8ea3SFrançois Revol 	if (message->WasDropped()) {
900c28f8ea3SFrançois Revol 		rgb_color* color;
901c28f8ea3SFrançois Revol 		ssize_t size;
9021201d52eSAxel Dörfler 		if (message->FindData("RGBColor", B_RGB_COLOR_TYPE, 0,
9031201d52eSAxel Dörfler 				(const void**)&color, &size) == B_OK
9049c89c450SAxel Dörfler 			&& size == sizeof(rgb_color)) {
9059c89c450SAxel Dörfler 			BPoint dropPoint = message->DropPoint();
906c28f8ea3SFrançois Revol 			ConvertFromScreen(&dropPoint);
9079c89c450SAxel Dörfler 
908c28f8ea3SFrançois Revol 			if (_HistoryFrame().Contains(dropPoint)) {
9099c89c450SAxel Dörfler 				fHistoryBackgroundColor = *color;
9109c89c450SAxel Dörfler 				Invalidate(_HistoryFrame());
911c28f8ea3SFrançois Revol 			} else {
9125f2f72a2SFrançois Revol 				// check each legend color box
913d4216445SAxel Dörfler 				BAutolock _(fSourcesLock);
914d4216445SAxel Dörfler 
9155f2f72a2SFrançois Revol 				BRect legendFrame = _LegendFrame();
9169c89c450SAxel Dörfler 				for (int32 i = 0; i < fSources.CountItems(); i++) {
9171201d52eSAxel Dörfler 					BRect frame = _LegendColorFrameAt(legendFrame, i);
9189c89c450SAxel Dörfler 					if (frame.Contains(dropPoint)) {
9195f2f72a2SFrançois Revol 						fSources.ItemAt(i)->SetColor(*color);
9209c89c450SAxel Dörfler 						Invalidate(_HistoryFrame());
9211201d52eSAxel Dörfler 						Invalidate(frame);
9225f2f72a2SFrançois Revol 						return;
9235f2f72a2SFrançois Revol 					}
9245f2f72a2SFrançois Revol 				}
9259c89c450SAxel Dörfler 
9269c89c450SAxel Dörfler 				if (dynamic_cast<ActivityMonitor*>(be_app) == NULL) {
9279c89c450SAxel Dörfler 					// allow background color change in the replicant only
9289c89c450SAxel Dörfler 					fLegendBackgroundColor = *color;
9291201d52eSAxel Dörfler 					SetLowColor(fLegendBackgroundColor);
9309c89c450SAxel Dörfler 					Invalidate(legendFrame);
9319c89c450SAxel Dörfler 				}
932c28f8ea3SFrançois Revol 			}
933c28f8ea3SFrançois Revol 			return;
934c28f8ea3SFrançois Revol 		}
9359c89c450SAxel Dörfler 	}
9369c89c450SAxel Dörfler 
93718d3e65eSAxel Dörfler 	switch (message->what) {
93818d3e65eSAxel Dörfler 		case B_ABOUT_REQUESTED:
93918d3e65eSAxel Dörfler 			ActivityMonitor::ShowAbout();
94018d3e65eSAxel Dörfler 			break;
94118d3e65eSAxel Dörfler 
94218d3e65eSAxel Dörfler 		case kMsgToggleDataSource:
94318d3e65eSAxel Dörfler 		{
94418d3e65eSAxel Dörfler 			int32 index;
94518d3e65eSAxel Dörfler 			if (message->FindInt32("index", &index) != B_OK)
94618d3e65eSAxel Dörfler 				break;
94718d3e65eSAxel Dörfler 
94818d3e65eSAxel Dörfler 			const DataSource* baseSource = DataSource::SourceAt(index);
94918d3e65eSAxel Dörfler 			if (baseSource == NULL)
95018d3e65eSAxel Dörfler 				break;
95118d3e65eSAxel Dörfler 
9523a4a2141SAxel Dörfler 			DataSource* source = FindDataSource(baseSource);
95318d3e65eSAxel Dörfler 			if (source == NULL)
9543a4a2141SAxel Dörfler 				AddDataSource(baseSource);
95518d3e65eSAxel Dörfler 			else
95618d3e65eSAxel Dörfler 				RemoveDataSource(source);
95718d3e65eSAxel Dörfler 
95818d3e65eSAxel Dörfler 			Invalidate();
95918d3e65eSAxel Dörfler 			break;
96018d3e65eSAxel Dörfler 		}
96118d3e65eSAxel Dörfler 
9623a4a2141SAxel Dörfler 		case kMsgToggleLegend:
9633a4a2141SAxel Dörfler 			fShowLegend = !fShowLegend;
9643a4a2141SAxel Dörfler 			Invalidate();
9653a4a2141SAxel Dörfler 			break;
9663a4a2141SAxel Dörfler 
96718d3e65eSAxel Dörfler 		case B_MOUSE_WHEEL_CHANGED:
96818d3e65eSAxel Dörfler 		{
96918d3e65eSAxel Dörfler 			float deltaY = 0.0f;
97018d3e65eSAxel Dörfler 			if (message->FindFloat("be:wheel_delta_y", &deltaY) != B_OK
97118d3e65eSAxel Dörfler 				|| deltaY == 0.0f)
97218d3e65eSAxel Dörfler 				break;
97318d3e65eSAxel Dörfler 
97418d3e65eSAxel Dörfler 			if (deltaY > 0)
97518d3e65eSAxel Dörfler 				fDrawResolution *= 2;
97618d3e65eSAxel Dörfler 			else
97718d3e65eSAxel Dörfler 				fDrawResolution /= 2;
97818d3e65eSAxel Dörfler 
97918d3e65eSAxel Dörfler 			if (fDrawResolution < 1)
98018d3e65eSAxel Dörfler 				fDrawResolution = 1;
98118d3e65eSAxel Dörfler 			if (fDrawResolution > 128)
98218d3e65eSAxel Dörfler 				fDrawResolution = 128;
98318d3e65eSAxel Dörfler 
98418d3e65eSAxel Dörfler 			Invalidate();
98518d3e65eSAxel Dörfler 			break;
98618d3e65eSAxel Dörfler 		}
98718d3e65eSAxel Dörfler 
98818d3e65eSAxel Dörfler 		default:
98918d3e65eSAxel Dörfler 			BView::MessageReceived(message);
99018d3e65eSAxel Dörfler 			break;
99118d3e65eSAxel Dörfler 	}
99218d3e65eSAxel Dörfler }
99318d3e65eSAxel Dörfler 
99418d3e65eSAxel Dörfler 
995065e8de0SAxel Dörfler void
996065e8de0SAxel Dörfler ActivityView::_UpdateFrame()
997065e8de0SAxel Dörfler {
998dc1ffc79SFrançois Revol #ifdef __HAIKU__
999065e8de0SAxel Dörfler 	if (fLegendLayoutItem == NULL || fHistoryLayoutItem == NULL)
1000065e8de0SAxel Dörfler 		return;
1001065e8de0SAxel Dörfler 
1002065e8de0SAxel Dörfler 	BRect historyFrame = fHistoryLayoutItem->Frame();
1003065e8de0SAxel Dörfler 	BRect legendFrame = fLegendLayoutItem->Frame();
1004dc1ffc79SFrançois Revol #else
1005dc1ffc79SFrançois Revol 	BRect historyFrame = Bounds();
1006dc1ffc79SFrançois Revol 	BRect legendFrame = Bounds();
1007dc1ffc79SFrançois Revol 	historyFrame.bottom -= 2 * Bounds().Height() / 3;
1008dc1ffc79SFrançois Revol 	legendFrame.top += Bounds().Height() / 3;
1009dc1ffc79SFrançois Revol #endif
1010065e8de0SAxel Dörfler 	MoveTo(historyFrame.left, historyFrame.top);
1011065e8de0SAxel Dörfler 	ResizeTo(legendFrame.left + legendFrame.Width() - historyFrame.left,
1012065e8de0SAxel Dörfler 		legendFrame.top + legendFrame.Height() - historyFrame.top);
1013065e8de0SAxel Dörfler }
1014065e8de0SAxel Dörfler 
1015065e8de0SAxel Dörfler 
10163a4a2141SAxel Dörfler BRect
10173a4a2141SAxel Dörfler ActivityView::_HistoryFrame() const
10183a4a2141SAxel Dörfler {
10193a4a2141SAxel Dörfler 	if (!fShowLegend)
10203a4a2141SAxel Dörfler 		return Bounds();
10213a4a2141SAxel Dörfler 
10223a4a2141SAxel Dörfler 	BRect frame = Bounds();
10233a4a2141SAxel Dörfler 	BRect legendFrame = _LegendFrame();
10243a4a2141SAxel Dörfler 
10253a4a2141SAxel Dörfler 	frame.bottom = legendFrame.top - 1;
10263a4a2141SAxel Dörfler 
10273a4a2141SAxel Dörfler 	return frame;
10283a4a2141SAxel Dörfler }
10293a4a2141SAxel Dörfler 
10303a4a2141SAxel Dörfler 
1031065e8de0SAxel Dörfler float
1032065e8de0SAxel Dörfler ActivityView::_LegendHeight() const
10333a4a2141SAxel Dörfler {
10343a4a2141SAxel Dörfler 	font_height fontHeight;
10353a4a2141SAxel Dörfler 	GetFontHeight(&fontHeight);
10363a4a2141SAxel Dörfler 
1037d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
1038d4216445SAxel Dörfler 
10393a4a2141SAxel Dörfler 	int32 rows = (fSources.CountItems() + 1) / 2;
1040065e8de0SAxel Dörfler 	return rows * (4 + ceilf(fontHeight.ascent)
10413a4a2141SAxel Dörfler 		+ ceilf(fontHeight.descent) + ceilf(fontHeight.leading));
1042065e8de0SAxel Dörfler }
1043065e8de0SAxel Dörfler 
1044065e8de0SAxel Dörfler 
1045065e8de0SAxel Dörfler BRect
1046065e8de0SAxel Dörfler ActivityView::_LegendFrame() const
1047065e8de0SAxel Dörfler {
1048065e8de0SAxel Dörfler 	float height;
1049dc1ffc79SFrançois Revol #ifdef __HAIKU__
1050065e8de0SAxel Dörfler 	if (fLegendLayoutItem != NULL)
1051065e8de0SAxel Dörfler 		height = fLegendLayoutItem->Frame().Height();
1052065e8de0SAxel Dörfler 	else
1053dc1ffc79SFrançois Revol #endif
1054065e8de0SAxel Dörfler 		height = _LegendHeight();
1055065e8de0SAxel Dörfler 
1056065e8de0SAxel Dörfler 	BRect frame = Bounds();
1057065e8de0SAxel Dörfler 	frame.top = frame.bottom - height;
10583a4a2141SAxel Dörfler 
10593a4a2141SAxel Dörfler 	return frame;
10603a4a2141SAxel Dörfler }
10613a4a2141SAxel Dörfler 
10623a4a2141SAxel Dörfler 
10633a4a2141SAxel Dörfler BRect
10643a4a2141SAxel Dörfler ActivityView::_LegendFrameAt(BRect frame, int32 index) const
10653a4a2141SAxel Dörfler {
10663a4a2141SAxel Dörfler 	int32 column = index & 1;
10673a4a2141SAxel Dörfler 	int32 row = index / 2;
10683a4a2141SAxel Dörfler 	if (column == 0)
10693a4a2141SAxel Dörfler 		frame.right = frame.left + floorf(frame.Width() / 2) - 5;
10703a4a2141SAxel Dörfler 	else
10713a4a2141SAxel Dörfler 		frame.left = frame.right - floorf(frame.Width() / 2) + 5;
10723a4a2141SAxel Dörfler 
1073d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
1074d4216445SAxel Dörfler 
10753a4a2141SAxel Dörfler 	int32 rows = (fSources.CountItems() + 1) / 2;
10763a4a2141SAxel Dörfler 	float height = floorf((frame.Height() - 5) / rows);
10773a4a2141SAxel Dörfler 
10783a4a2141SAxel Dörfler 	frame.top = frame.top + 5 + row * height;
10793a4a2141SAxel Dörfler 	frame.bottom = frame.top + height - 1;
10803a4a2141SAxel Dörfler 
10813a4a2141SAxel Dörfler 	return frame;
10823a4a2141SAxel Dörfler }
10833a4a2141SAxel Dörfler 
10843a4a2141SAxel Dörfler 
10851201d52eSAxel Dörfler BRect
10861201d52eSAxel Dörfler ActivityView::_LegendColorFrameAt(BRect frame, int32 index) const
10871201d52eSAxel Dörfler {
10881201d52eSAxel Dörfler 	frame = _LegendFrameAt(frame, index);
10891201d52eSAxel Dörfler 	frame.InsetBy(1, 1);
10901201d52eSAxel Dörfler 	frame.right = frame.left + frame.Height();
10911201d52eSAxel Dörfler 
10921201d52eSAxel Dörfler 	return frame;
10931201d52eSAxel Dörfler }
10941201d52eSAxel Dörfler 
10951201d52eSAxel Dörfler 
109618d3e65eSAxel Dörfler float
109718d3e65eSAxel Dörfler ActivityView::_PositionForValue(DataSource* source, DataHistory* values,
109818d3e65eSAxel Dörfler 	int64 value)
109918d3e65eSAxel Dörfler {
110018d3e65eSAxel Dörfler 	int64 min = source->Minimum();
110118d3e65eSAxel Dörfler 	int64 max = source->Maximum();
110218d3e65eSAxel Dörfler 	if (source->AdaptiveScale()) {
110318d3e65eSAxel Dörfler 		int64 adaptiveMax = int64(values->MaximumValue() * 1.2);
110418d3e65eSAxel Dörfler 		if (adaptiveMax < max)
110518d3e65eSAxel Dörfler 			max = adaptiveMax;
110618d3e65eSAxel Dörfler 	}
110718d3e65eSAxel Dörfler 
110818d3e65eSAxel Dörfler 	if (value > max)
110918d3e65eSAxel Dörfler 		value = max;
111018d3e65eSAxel Dörfler 	if (value < min)
111118d3e65eSAxel Dörfler 		value = min;
111218d3e65eSAxel Dörfler 
11133a4a2141SAxel Dörfler 	float height = _HistoryFrame().Height();
111418d3e65eSAxel Dörfler 	return height - (value - min) * height / (max - min);
111518d3e65eSAxel Dörfler }
111618d3e65eSAxel Dörfler 
111718d3e65eSAxel Dörfler 
111818d3e65eSAxel Dörfler void
11193a4a2141SAxel Dörfler ActivityView::_DrawHistory()
112018d3e65eSAxel Dörfler {
11213a4a2141SAxel Dörfler 	_UpdateOffscreenBitmap();
11223a4a2141SAxel Dörfler 
11233a4a2141SAxel Dörfler 	BView* view = this;
11243a4a2141SAxel Dörfler 	if (fOffscreen != NULL) {
11253a4a2141SAxel Dörfler 		fOffscreen->Lock();
11269c89c450SAxel Dörfler 		view = _OffscreenView();
11273a4a2141SAxel Dörfler 	}
11283a4a2141SAxel Dörfler 
11293a4a2141SAxel Dörfler 	BRect frame = _HistoryFrame();
11301201d52eSAxel Dörfler 	view->SetLowColor(fHistoryBackgroundColor);
11313a4a2141SAxel Dörfler 	view->FillRect(frame, B_SOLID_LOW);
11323a4a2141SAxel Dörfler 
113318d3e65eSAxel Dörfler 	uint32 step = 2;
113418d3e65eSAxel Dörfler 	uint32 resolution = fDrawResolution;
113518d3e65eSAxel Dörfler 	if (fDrawResolution > 1) {
113618d3e65eSAxel Dörfler 		step = 1;
113718d3e65eSAxel Dörfler 		resolution--;
113818d3e65eSAxel Dörfler 	}
113918d3e65eSAxel Dörfler 
11403a4a2141SAxel Dörfler 	uint32 width = frame.IntegerWidth() - 10;
114118d3e65eSAxel Dörfler 	uint32 steps = width / step;
114218d3e65eSAxel Dörfler 	bigtime_t timeStep = fRefreshInterval * resolution;
114318d3e65eSAxel Dörfler 	bigtime_t now = system_time();
114418d3e65eSAxel Dörfler 
11451201d52eSAxel Dörfler 	// Draw scale
11461201d52eSAxel Dörfler 	// TODO: add second markers?
11471201d52eSAxel Dörfler 
11483a4a2141SAxel Dörfler 	view->SetPenSize(1);
11493a4a2141SAxel Dörfler 
11501201d52eSAxel Dörfler 	rgb_color scaleColor = view->LowColor();
11511201d52eSAxel Dörfler 	uint32 average = (scaleColor.red + scaleColor.green + scaleColor.blue) / 3;
11521201d52eSAxel Dörfler 	if (average < 96)
11531201d52eSAxel Dörfler 		scaleColor = tint_color(scaleColor, B_LIGHTEN_2_TINT);
11541201d52eSAxel Dörfler 	else
11551201d52eSAxel Dörfler 		scaleColor = tint_color(scaleColor, B_DARKEN_2_TINT);
11561201d52eSAxel Dörfler 
11571201d52eSAxel Dörfler 	view->SetHighColor(scaleColor);
11583a4a2141SAxel Dörfler 	view->StrokeRect(frame);
11593a4a2141SAxel Dörfler 	view->StrokeLine(BPoint(frame.left, frame.top + frame.Height() / 2),
11603a4a2141SAxel Dörfler 		BPoint(frame.right, frame.top + frame.Height() / 2));
11613a4a2141SAxel Dörfler 
11621201d52eSAxel Dörfler 	// Draw values
11631201d52eSAxel Dörfler 
11643a4a2141SAxel Dörfler 	view->SetPenSize(2);
1165d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
116618d3e65eSAxel Dörfler 
116718d3e65eSAxel Dörfler 	for (uint32 i = fSources.CountItems(); i-- > 0;) {
116818d3e65eSAxel Dörfler 		DataSource* source = fSources.ItemAt(i);
116918d3e65eSAxel Dörfler 		DataHistory* values = fValues.ItemAt(i);
117018d3e65eSAxel Dörfler 		bigtime_t time = now - steps * timeStep;
117118d3e65eSAxel Dörfler 			// for now steps pixels per second
117218d3e65eSAxel Dörfler 
11733a4a2141SAxel Dörfler 		view->BeginLineArray(steps);
11743a4a2141SAxel Dörfler 		view->SetHighColor(source->Color());
117518d3e65eSAxel Dörfler 
117618d3e65eSAxel Dörfler 		float lastY = FLT_MIN;
117718d3e65eSAxel Dörfler 		uint32 lastX = 0;
117818d3e65eSAxel Dörfler 
117918d3e65eSAxel Dörfler 		for (uint32 x = 0; x < width; x += step, time += timeStep) {
118018d3e65eSAxel Dörfler 			// TODO: compute starting point instead!
118118d3e65eSAxel Dörfler 			if (values->Start() > time || values->End() < time)
118218d3e65eSAxel Dörfler 				continue;
118318d3e65eSAxel Dörfler 
118418d3e65eSAxel Dörfler 			int64 value = values->ValueAt(time);
118518d3e65eSAxel Dörfler 			if (timeStep > fRefreshInterval) {
118618d3e65eSAxel Dörfler 				// TODO: always start with the same index, so that it always
118718d3e65eSAxel Dörfler 				// uses the same values for computation (currently it jumps)
118818d3e65eSAxel Dörfler 				uint32 count = 1;
118918d3e65eSAxel Dörfler 				for (bigtime_t offset = fRefreshInterval; offset < timeStep;
119018d3e65eSAxel Dörfler 						offset += fRefreshInterval) {
119118d3e65eSAxel Dörfler 					// TODO: handle int64 overflow correctly!
119218d3e65eSAxel Dörfler 					value += values->ValueAt(time + offset);
119318d3e65eSAxel Dörfler 					count++;
119418d3e65eSAxel Dörfler 				}
119518d3e65eSAxel Dörfler 				value /= count;
119618d3e65eSAxel Dörfler 			}
119718d3e65eSAxel Dörfler 
119818d3e65eSAxel Dörfler 			float y = _PositionForValue(source, values, value);
11993a4a2141SAxel Dörfler 			if (lastY != FLT_MIN) {
12003a4a2141SAxel Dörfler 				view->AddLine(BPoint(lastX, lastY), BPoint(x, y),
12013a4a2141SAxel Dörfler 					source->Color());
12023a4a2141SAxel Dörfler 			}
120318d3e65eSAxel Dörfler 
120418d3e65eSAxel Dörfler 			lastX = x;
120518d3e65eSAxel Dörfler 			lastY = y;
120618d3e65eSAxel Dörfler 		}
120718d3e65eSAxel Dörfler 
12083a4a2141SAxel Dörfler 		view->EndLineArray();
120918d3e65eSAxel Dörfler 	}
121018d3e65eSAxel Dörfler 
121118d3e65eSAxel Dörfler 	// TODO: add marks when an app started or quit
12123a4a2141SAxel Dörfler 	view->Sync();
12133a4a2141SAxel Dörfler 	if (fOffscreen != NULL) {
12143a4a2141SAxel Dörfler 		fOffscreen->Unlock();
12153a4a2141SAxel Dörfler 		DrawBitmap(fOffscreen);
12163a4a2141SAxel Dörfler 	}
12173a4a2141SAxel Dörfler }
12183a4a2141SAxel Dörfler 
12193a4a2141SAxel Dörfler 
12203a4a2141SAxel Dörfler void
12213a4a2141SAxel Dörfler ActivityView::Draw(BRect /*updateRect*/)
12223a4a2141SAxel Dörfler {
12233a4a2141SAxel Dörfler 	_DrawHistory();
12243a4a2141SAxel Dörfler 
12253a4a2141SAxel Dörfler 	if (!fShowLegend)
12263a4a2141SAxel Dörfler 		return;
12273a4a2141SAxel Dörfler 
12283a4a2141SAxel Dörfler 	// draw legend
12293a4a2141SAxel Dörfler 
1230d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
12313a4a2141SAxel Dörfler 	BRect legendFrame = _LegendFrame();
12329c89c450SAxel Dörfler 
12339c89c450SAxel Dörfler 	SetLowColor(fLegendBackgroundColor);
12343a4a2141SAxel Dörfler 	FillRect(legendFrame, B_SOLID_LOW);
12353a4a2141SAxel Dörfler 
12363a4a2141SAxel Dörfler 	font_height fontHeight;
12373a4a2141SAxel Dörfler 	GetFontHeight(&fontHeight);
12383a4a2141SAxel Dörfler 
12393a4a2141SAxel Dörfler 	for (int32 i = 0; i < fSources.CountItems(); i++) {
12403a4a2141SAxel Dörfler 		DataSource* source = fSources.ItemAt(i);
12413a4a2141SAxel Dörfler 		DataHistory* values = fValues.ItemAt(i);
12423a4a2141SAxel Dörfler 		BRect frame = _LegendFrameAt(legendFrame, i);
12433a4a2141SAxel Dörfler 
12443a4a2141SAxel Dörfler 		// draw color box
12451201d52eSAxel Dörfler 		BRect colorBox = _LegendColorFrameAt(legendFrame, i);
12463a4a2141SAxel Dörfler 		SetHighColor(tint_color(source->Color(), B_DARKEN_1_TINT));
12473a4a2141SAxel Dörfler 		StrokeRect(colorBox);
12483a4a2141SAxel Dörfler 		SetHighColor(source->Color());
12493a4a2141SAxel Dörfler 		colorBox.InsetBy(1, 1);
12503a4a2141SAxel Dörfler 		FillRect(colorBox);
12513a4a2141SAxel Dörfler 
12523a4a2141SAxel Dörfler 		// show current value and label
12533a4a2141SAxel Dörfler 		float y = frame.top + ceilf(fontHeight.ascent);
12543a4a2141SAxel Dörfler 		int64 value = values->ValueAt(values->End());
12553a4a2141SAxel Dörfler 		BString text;
12563a4a2141SAxel Dörfler 		source->Print(text, value);
12573a4a2141SAxel Dörfler 		float width = StringWidth(text.String());
12583a4a2141SAxel Dörfler 
12593a4a2141SAxel Dörfler 		BString label = source->Label();
12603a4a2141SAxel Dörfler 		TruncateString(&label, B_TRUNCATE_MIDDLE,
12613a4a2141SAxel Dörfler 			frame.right - colorBox.right - 12 - width);
12623a4a2141SAxel Dörfler 
12633a4a2141SAxel Dörfler 		SetHighColor(ui_color(B_CONTROL_TEXT_COLOR));
12643a4a2141SAxel Dörfler 		DrawString(label.String(), BPoint(6 + colorBox.right, y));
12653a4a2141SAxel Dörfler 		DrawString(text.String(), BPoint(frame.right - width, y));
12663a4a2141SAxel Dörfler 	}
126718d3e65eSAxel Dörfler }
126818d3e65eSAxel Dörfler 
126918d3e65eSAxel Dörfler 
127018d3e65eSAxel Dörfler void
127118d3e65eSAxel Dörfler ActivityView::_Refresh()
127218d3e65eSAxel Dörfler {
1273d4216445SAxel Dörfler 	bigtime_t lastTimeout = system_time() - fRefreshInterval;
12744ce1e1d2SAxel Dörfler 	BMessenger target(this);
127518d3e65eSAxel Dörfler 
1276d4216445SAxel Dörfler 	while (true) {
1277d4216445SAxel Dörfler 		status_t status = acquire_sem_etc(fRefreshSem, 1, B_ABSOLUTE_TIMEOUT,
1278d4216445SAxel Dörfler 			lastTimeout + fRefreshInterval);
1279d4216445SAxel Dörfler 		if (status == B_OK || status == B_BAD_SEM_ID)
1280d4216445SAxel Dörfler 			break;
1281d4216445SAxel Dörfler 		if (status == B_INTERRUPTED)
1282d4216445SAxel Dörfler 			continue;
1283d4216445SAxel Dörfler 
1284d4216445SAxel Dörfler 		SystemInfo info(fSystemInfoHandler);
1285d4216445SAxel Dörfler 		lastTimeout += fRefreshInterval;
1286d4216445SAxel Dörfler 
1287d4216445SAxel Dörfler 		fSourcesLock.Lock();
128818d3e65eSAxel Dörfler 
128918d3e65eSAxel Dörfler 		for (uint32 i = fSources.CountItems(); i-- > 0;) {
129018d3e65eSAxel Dörfler 			DataSource* source = fSources.ItemAt(i);
129118d3e65eSAxel Dörfler 			DataHistory* values = fValues.ItemAt(i);
129218d3e65eSAxel Dörfler 
129318d3e65eSAxel Dörfler 			int64 value = source->NextValue(info);
129418d3e65eSAxel Dörfler 			values->AddValue(info.Time(), value);
129518d3e65eSAxel Dörfler 		}
129618d3e65eSAxel Dörfler 
1297d4216445SAxel Dörfler 		fSourcesLock.Unlock();
1298d4216445SAxel Dörfler 
129918d3e65eSAxel Dörfler 		bigtime_t now = info.Time();
130018d3e65eSAxel Dörfler 		if (fLastRefresh + fDrawInterval <= now) {
13014ce1e1d2SAxel Dörfler 			target.SendMessage(B_INVALIDATE);
130218d3e65eSAxel Dörfler 			fLastRefresh = now;
130318d3e65eSAxel Dörfler 		}
130418d3e65eSAxel Dörfler 	}
1305d4216445SAxel Dörfler }
130618d3e65eSAxel Dörfler 
1307d4216445SAxel Dörfler 
1308d4216445SAxel Dörfler /*static*/ status_t
1309d4216445SAxel Dörfler ActivityView::_RefreshThread(void* self)
1310d4216445SAxel Dörfler {
1311d4216445SAxel Dörfler 	((ActivityView*)self)->_Refresh();
1312d4216445SAxel Dörfler 	return B_OK;
1313d4216445SAxel Dörfler }
1314