xref: /haiku/src/apps/activitymonitor/ActivityView.cpp (revision 7974d3dcf39ce78e5885b481eee12e561ad6e096)
118d3e65eSAxel Dörfler /*
21bb87bd0SAxel Dörfler  * Copyright 2008-2009, Axel Dörfler, axeld@pinc-software.de.
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>
12cce423c2SRene Gollent #include <vector>
1318d3e65eSAxel Dörfler 
14dc1ffc79SFrançois Revol #ifdef __HAIKU__
15065e8de0SAxel Dörfler #	include <AbstractLayoutItem.h>
16ed1b2753SStephan Aßmus #	include <ControlLook.h>
17dc1ffc79SFrançois Revol #endif
1818d3e65eSAxel Dörfler #include <Application.h>
19d4216445SAxel Dörfler #include <Autolock.h>
2018d3e65eSAxel Dörfler #include <Bitmap.h>
2118d3e65eSAxel Dörfler #include <Dragger.h>
2218d3e65eSAxel Dörfler #include <MenuItem.h>
2318d3e65eSAxel Dörfler #include <MessageRunner.h>
2418d3e65eSAxel Dörfler #include <PopUpMenu.h>
258e26f387SAxel Dörfler #include <Shape.h>
2618d3e65eSAxel Dörfler #include <String.h>
2718d3e65eSAxel Dörfler 
2818d3e65eSAxel Dörfler #include "ActivityMonitor.h"
293f315b26SAxel Dörfler #include "ActivityWindow.h"
301bb87bd0SAxel Dörfler #include "SettingsWindow.h"
3118d3e65eSAxel Dörfler #include "SystemInfo.h"
3274158bb4SFrançois Revol #include "SystemInfoHandler.h"
3318d3e65eSAxel Dörfler 
3418d3e65eSAxel Dörfler 
358e26f387SAxel Dörfler template<typename ObjectType>
368e26f387SAxel Dörfler class ListAddDeleter {
378e26f387SAxel Dörfler public:
388e26f387SAxel Dörfler 	ListAddDeleter(BObjectList<ObjectType>& list, ObjectType* object,
398e26f387SAxel Dörfler 			int32 spot)
408e26f387SAxel Dörfler 		:
418e26f387SAxel Dörfler 		fList(list),
428e26f387SAxel Dörfler 		fObject(object)
438e26f387SAxel Dörfler 	{
448e26f387SAxel Dörfler 		if (fObject != NULL && !fList.AddItem(fObject, spot)) {
458e26f387SAxel Dörfler 			delete fObject;
468e26f387SAxel Dörfler 			fObject = NULL;
478e26f387SAxel Dörfler 		}
488e26f387SAxel Dörfler 	}
498e26f387SAxel Dörfler 
508e26f387SAxel Dörfler 	~ListAddDeleter()
518e26f387SAxel Dörfler 	{
528e26f387SAxel Dörfler 		if (fObject != NULL) {
538e26f387SAxel Dörfler 			fList.RemoveItem(fObject);
548e26f387SAxel Dörfler 			delete fObject;
558e26f387SAxel Dörfler 		}
568e26f387SAxel Dörfler 	}
578e26f387SAxel Dörfler 
588e26f387SAxel Dörfler 	bool Failed() const
598e26f387SAxel Dörfler 	{
608e26f387SAxel Dörfler 		return fObject == NULL;
618e26f387SAxel Dörfler 	}
628e26f387SAxel Dörfler 
638e26f387SAxel Dörfler 	void Detach()
648e26f387SAxel Dörfler 	{
658e26f387SAxel Dörfler 		fObject = NULL;
668e26f387SAxel Dörfler 	}
678e26f387SAxel Dörfler 
688e26f387SAxel Dörfler private:
698e26f387SAxel Dörfler 	BObjectList<ObjectType>&	fList;
708e26f387SAxel Dörfler 	ObjectType*					fObject;
718e26f387SAxel Dörfler };
728e26f387SAxel Dörfler 
738e26f387SAxel Dörfler 
748e26f387SAxel Dörfler /*!	This class manages the scale of a history with a dynamic scale.
758e26f387SAxel Dörfler 	Every history value will be input via Update(), and the minimum/maximum
768e26f387SAxel Dörfler 	is computed from that.
778e26f387SAxel Dörfler */
7851591198SAxel Dörfler class Scale {
7951591198SAxel Dörfler public:
8051591198SAxel Dörfler 								Scale(scale_type type);
8151591198SAxel Dörfler 
8251591198SAxel Dörfler 			int64				MinimumValue() const { return fMinimumValue; }
8351591198SAxel Dörfler 			int64				MaximumValue() const { return fMaximumValue; }
8451591198SAxel Dörfler 
8551591198SAxel Dörfler 			void				Update(int64 value);
8651591198SAxel Dörfler 
8751591198SAxel Dörfler private:
8851591198SAxel Dörfler 			scale_type			fType;
8951591198SAxel Dörfler 			int64				fMinimumValue;
9051591198SAxel Dörfler 			int64				fMaximumValue;
9151591198SAxel Dörfler 			bool				fInitialized;
9251591198SAxel Dörfler };
9351591198SAxel Dörfler 
948e26f387SAxel Dörfler /*!	Stores the interpolated on screen view values. This is done so that the
958e26f387SAxel Dörfler 	interpolation is fixed, and does not change when being scrolled.
968e26f387SAxel Dörfler 
978e26f387SAxel Dörfler 	We could also just do this by making sure we always ask for the same
988e26f387SAxel Dörfler 	interval only, but this way we also save the interpolation.
998e26f387SAxel Dörfler */
1008e26f387SAxel Dörfler class ViewHistory {
1018e26f387SAxel Dörfler public:
1028e26f387SAxel Dörfler 								ViewHistory();
1038e26f387SAxel Dörfler 
1048e26f387SAxel Dörfler 			int64				ValueAt(int32 x);
1058e26f387SAxel Dörfler 
1068e26f387SAxel Dörfler 			int32				Start() const
1078e26f387SAxel Dörfler 									{ return fValues.Size()
1088e26f387SAxel Dörfler 										- fValues.CountItems(); }
1098e26f387SAxel Dörfler 
1108e26f387SAxel Dörfler 			void				Update(DataHistory* history, int32 width,
1118e26f387SAxel Dörfler 									int32 resolution, bigtime_t toTime,
1128e26f387SAxel Dörfler 									bigtime_t step, bigtime_t refresh);
1138e26f387SAxel Dörfler 
1148e26f387SAxel Dörfler private:
1158e26f387SAxel Dörfler 			CircularBuffer<int64> fValues;
1168e26f387SAxel Dörfler 			int32				fResolution;
1178e26f387SAxel Dörfler 			bigtime_t			fRefresh;
1188e26f387SAxel Dörfler 			bigtime_t			fLastTime;
1198e26f387SAxel Dörfler };
1208e26f387SAxel Dörfler 
12118d3e65eSAxel Dörfler struct data_item {
12218d3e65eSAxel Dörfler 	bigtime_t	time;
12318d3e65eSAxel Dörfler 	int64		value;
12418d3e65eSAxel Dörfler };
12518d3e65eSAxel Dörfler 
126dc1ffc79SFrançois Revol #ifdef __HAIKU__
127065e8de0SAxel Dörfler class ActivityView::HistoryLayoutItem : public BAbstractLayoutItem {
128065e8de0SAxel Dörfler public:
129065e8de0SAxel Dörfler 							HistoryLayoutItem(ActivityView* parent);
130065e8de0SAxel Dörfler 
131065e8de0SAxel Dörfler 	virtual	bool			IsVisible();
132065e8de0SAxel Dörfler 	virtual	void			SetVisible(bool visible);
133065e8de0SAxel Dörfler 
134065e8de0SAxel Dörfler 	virtual	BRect			Frame();
135065e8de0SAxel Dörfler 	virtual	void			SetFrame(BRect frame);
136065e8de0SAxel Dörfler 
137065e8de0SAxel Dörfler 	virtual	BView*			View();
138065e8de0SAxel Dörfler 
139065e8de0SAxel Dörfler 	virtual	BSize			BasePreferredSize();
140065e8de0SAxel Dörfler 
141065e8de0SAxel Dörfler private:
142065e8de0SAxel Dörfler 	ActivityView*			fParent;
143065e8de0SAxel Dörfler 	BRect					fFrame;
144065e8de0SAxel Dörfler };
145065e8de0SAxel Dörfler 
146065e8de0SAxel Dörfler class ActivityView::LegendLayoutItem : public BAbstractLayoutItem {
147065e8de0SAxel Dörfler public:
148065e8de0SAxel Dörfler 							LegendLayoutItem(ActivityView* parent);
149065e8de0SAxel Dörfler 
150065e8de0SAxel Dörfler 	virtual	bool			IsVisible();
151065e8de0SAxel Dörfler 	virtual	void			SetVisible(bool visible);
152065e8de0SAxel Dörfler 
153065e8de0SAxel Dörfler 	virtual	BRect			Frame();
154065e8de0SAxel Dörfler 	virtual	void			SetFrame(BRect frame);
155065e8de0SAxel Dörfler 
156065e8de0SAxel Dörfler 	virtual	BView*			View();
157065e8de0SAxel Dörfler 
158065e8de0SAxel Dörfler 	virtual	BSize			BaseMinSize();
159065e8de0SAxel Dörfler 	virtual	BSize			BaseMaxSize();
160065e8de0SAxel Dörfler 	virtual	BSize			BasePreferredSize();
161065e8de0SAxel Dörfler 	virtual	BAlignment		BaseAlignment();
162065e8de0SAxel Dörfler 
163065e8de0SAxel Dörfler private:
164065e8de0SAxel Dörfler 	ActivityView*			fParent;
165065e8de0SAxel Dörfler 	BRect					fFrame;
166065e8de0SAxel Dörfler };
167dc1ffc79SFrançois Revol #endif
168065e8de0SAxel Dörfler 
1691bb87bd0SAxel Dörfler const bigtime_t kInitialRefreshInterval = 250000LL;
17018d3e65eSAxel Dörfler 
17118d3e65eSAxel Dörfler const uint32 kMsgToggleDataSource = 'tgds';
1723a4a2141SAxel Dörfler const uint32 kMsgToggleLegend = 'tglg';
1731bb87bd0SAxel Dörfler const uint32 kMsgUpdateResolution = 'ures';
17418d3e65eSAxel Dörfler 
17518d3e65eSAxel Dörfler extern const char* kSignature;
17618d3e65eSAxel Dörfler 
17718d3e65eSAxel Dörfler 
17851591198SAxel Dörfler Scale::Scale(scale_type type)
17951591198SAxel Dörfler 	:
18051591198SAxel Dörfler 	fType(type),
18151591198SAxel Dörfler 	fMinimumValue(0),
18251591198SAxel Dörfler 	fMaximumValue(0),
18351591198SAxel Dörfler 	fInitialized(false)
18451591198SAxel Dörfler {
18551591198SAxel Dörfler }
18651591198SAxel Dörfler 
18751591198SAxel Dörfler 
18851591198SAxel Dörfler void
18951591198SAxel Dörfler Scale::Update(int64 value)
19051591198SAxel Dörfler {
19151591198SAxel Dörfler 	if (!fInitialized || fMinimumValue > value)
19251591198SAxel Dörfler 		fMinimumValue = value;
193230e3259SAxel Dörfler 	if (!fInitialized || fMaximumValue < value)
19451591198SAxel Dörfler 		fMaximumValue = value;
19551591198SAxel Dörfler 
19651591198SAxel Dörfler 	fInitialized = true;
19751591198SAxel Dörfler }
19851591198SAxel Dörfler 
19951591198SAxel Dörfler 
20051591198SAxel Dörfler //	#pragma mark -
20151591198SAxel Dörfler 
20251591198SAxel Dörfler 
2038e26f387SAxel Dörfler ViewHistory::ViewHistory()
2048e26f387SAxel Dörfler 	:
2058e26f387SAxel Dörfler 	fValues(1),
2068e26f387SAxel Dörfler 	fResolution(-1),
2078e26f387SAxel Dörfler 	fRefresh(-1),
2088e26f387SAxel Dörfler 	fLastTime(0)
2098e26f387SAxel Dörfler {
2108e26f387SAxel Dörfler }
2118e26f387SAxel Dörfler 
2128e26f387SAxel Dörfler 
2138e26f387SAxel Dörfler int64
2148e26f387SAxel Dörfler ViewHistory::ValueAt(int32 x)
2158e26f387SAxel Dörfler {
2168e26f387SAxel Dörfler 	int64* value = fValues.ItemAt(x - Start());
2178e26f387SAxel Dörfler 	if (value != NULL)
2188e26f387SAxel Dörfler 		return *value;
2198e26f387SAxel Dörfler 
2208e26f387SAxel Dörfler 	return 0;
2218e26f387SAxel Dörfler }
2228e26f387SAxel Dörfler 
2238e26f387SAxel Dörfler 
2248e26f387SAxel Dörfler void
2258e26f387SAxel Dörfler ViewHistory::Update(DataHistory* history, int32 width, int32 resolution,
2268e26f387SAxel Dörfler 	bigtime_t toTime, bigtime_t step, bigtime_t refresh)
2278e26f387SAxel Dörfler {
2282c604c0dSAxel Dörfler 	if (width > 16384) {
2292c604c0dSAxel Dörfler 		// ignore this - it seems the view hasn't been layouted yet
2302c604c0dSAxel Dörfler 		return;
2312c604c0dSAxel Dörfler 	}
2322c604c0dSAxel Dörfler 
2338e26f387SAxel Dörfler 	// Check if we need to invalidate the existing values
2348e26f387SAxel Dörfler 	if ((int32)fValues.Size() != width
2358e26f387SAxel Dörfler 		|| fResolution != resolution
2368e26f387SAxel Dörfler 		|| fRefresh != refresh) {
2378e26f387SAxel Dörfler 		fValues.SetSize(width);
2388e26f387SAxel Dörfler 		fResolution = resolution;
2398e26f387SAxel Dörfler 		fRefresh = refresh;
2407d33b63dSAxel Dörfler 		fLastTime = 0;
2418e26f387SAxel Dörfler 	}
2428e26f387SAxel Dörfler 
2438e26f387SAxel Dörfler 	// Compute how many new values we need to retrieve
2448e26f387SAxel Dörfler 	if (fLastTime < history->Start())
2458e26f387SAxel Dörfler 		fLastTime = history->Start();
2467d33b63dSAxel Dörfler 	if (fLastTime > history->End())
2477d33b63dSAxel Dörfler 		return;
2488e26f387SAxel Dörfler 
2498e26f387SAxel Dörfler 	int32 updateWidth = int32((toTime - fLastTime) / step);
2508e26f387SAxel Dörfler 	if (updateWidth < 1)
2518e26f387SAxel Dörfler 		return;
2528e26f387SAxel Dörfler 
2538e26f387SAxel Dörfler 	if (updateWidth > (int32)fValues.Size()) {
2548e26f387SAxel Dörfler 		updateWidth = fValues.Size();
2558e26f387SAxel Dörfler 		fLastTime = toTime - updateWidth * step;
2568e26f387SAxel Dörfler 	}
2578e26f387SAxel Dörfler 
2588e26f387SAxel Dörfler 	for (int32 i = 0; i < updateWidth; i++) {
2598e26f387SAxel Dörfler 		int64 value = history->ValueAt(fLastTime += step);
2608e26f387SAxel Dörfler 
2618e26f387SAxel Dörfler 		if (step > refresh) {
2628e26f387SAxel Dörfler 			uint32 count = 1;
2638e26f387SAxel Dörfler 			for (bigtime_t offset = refresh; offset < step; offset += refresh) {
2648e26f387SAxel Dörfler 				// TODO: handle int64 overflow correctly!
2658e26f387SAxel Dörfler 				value += history->ValueAt(fLastTime + offset);
2668e26f387SAxel Dörfler 				count++;
2678e26f387SAxel Dörfler 			}
2688e26f387SAxel Dörfler 			value /= count;
2698e26f387SAxel Dörfler 		}
2708e26f387SAxel Dörfler 
2718e26f387SAxel Dörfler 		fValues.AddItem(value);
2728e26f387SAxel Dörfler 	}
2738e26f387SAxel Dörfler }
2748e26f387SAxel Dörfler 
2758e26f387SAxel Dörfler 
2768e26f387SAxel Dörfler //	#pragma mark -
2778e26f387SAxel Dörfler 
2788e26f387SAxel Dörfler 
27918d3e65eSAxel Dörfler DataHistory::DataHistory(bigtime_t memorize, bigtime_t interval)
28018d3e65eSAxel Dörfler 	:
28118d3e65eSAxel Dörfler 	fBuffer(10000),
28218d3e65eSAxel Dörfler 	fMinimumValue(0),
28318d3e65eSAxel Dörfler 	fMaximumValue(0),
28418d3e65eSAxel Dörfler 	fRefreshInterval(interval),
28551591198SAxel Dörfler 	fLastIndex(-1),
28651591198SAxel Dörfler 	fScale(NULL)
28718d3e65eSAxel Dörfler {
28818d3e65eSAxel Dörfler }
28918d3e65eSAxel Dörfler 
29018d3e65eSAxel Dörfler 
29118d3e65eSAxel Dörfler DataHistory::~DataHistory()
29218d3e65eSAxel Dörfler {
29318d3e65eSAxel Dörfler }
29418d3e65eSAxel Dörfler 
29518d3e65eSAxel Dörfler 
29618d3e65eSAxel Dörfler void
29718d3e65eSAxel Dörfler DataHistory::AddValue(bigtime_t time, int64 value)
29818d3e65eSAxel Dörfler {
29918d3e65eSAxel Dörfler 	if (fBuffer.IsEmpty() || fMaximumValue < value)
30018d3e65eSAxel Dörfler 		fMaximumValue = value;
30118d3e65eSAxel Dörfler 	if (fBuffer.IsEmpty() || fMinimumValue > value)
30218d3e65eSAxel Dörfler 		fMinimumValue = value;
30351591198SAxel Dörfler 	if (fScale != NULL)
30451591198SAxel Dörfler 		fScale->Update(value);
30518d3e65eSAxel Dörfler 
30618d3e65eSAxel Dörfler 	data_item item = {time, value};
30718d3e65eSAxel Dörfler 	fBuffer.AddItem(item);
30818d3e65eSAxel Dörfler }
30918d3e65eSAxel Dörfler 
31018d3e65eSAxel Dörfler 
31118d3e65eSAxel Dörfler int64
31218d3e65eSAxel Dörfler DataHistory::ValueAt(bigtime_t time)
31318d3e65eSAxel Dörfler {
31451591198SAxel Dörfler 	int32 left = 0;
31551591198SAxel Dörfler 	int32 right = fBuffer.CountItems() - 1;
31651591198SAxel Dörfler 	data_item* item = NULL;
31751591198SAxel Dörfler 
31851591198SAxel Dörfler 	while (left <= right) {
31951591198SAxel Dörfler 		int32 index = (left + right) / 2;
32051591198SAxel Dörfler 		item = fBuffer.ItemAt(index);
32151591198SAxel Dörfler 
32251591198SAxel Dörfler 		if (item->time > time) {
32351591198SAxel Dörfler 			// search in left part
32451591198SAxel Dörfler 			right = index - 1;
32551591198SAxel Dörfler 		} else {
32684e23a5dSAxel Dörfler 			data_item* nextItem = fBuffer.ItemAt(index + 1);
32784e23a5dSAxel Dörfler 			if (nextItem == NULL)
32884e23a5dSAxel Dörfler 				return item->value;
32984e23a5dSAxel Dörfler 			if (nextItem->time > time) {
33051591198SAxel Dörfler 				// found item
33184e23a5dSAxel Dörfler 				int64 value = item->value;
33284e23a5dSAxel Dörfler 				value += int64(double(nextItem->value - value)
33384e23a5dSAxel Dörfler 					/ (nextItem->time - item->time) * (time - item->time));
3348e26f387SAxel Dörfler 				return value;
33551591198SAxel Dörfler 			}
33651591198SAxel Dörfler 
33751591198SAxel Dörfler 			// search in right part
33851591198SAxel Dörfler 			left = index + 1;
33951591198SAxel Dörfler 		}
34051591198SAxel Dörfler 	}
34118d3e65eSAxel Dörfler 
34218d3e65eSAxel Dörfler 	return 0;
34318d3e65eSAxel Dörfler }
34418d3e65eSAxel Dörfler 
34518d3e65eSAxel Dörfler 
34618d3e65eSAxel Dörfler int64
34718d3e65eSAxel Dörfler DataHistory::MaximumValue() const
34818d3e65eSAxel Dörfler {
34951591198SAxel Dörfler 	if (fScale != NULL)
35051591198SAxel Dörfler 		return fScale->MaximumValue();
35151591198SAxel Dörfler 
35218d3e65eSAxel Dörfler 	return fMaximumValue;
35318d3e65eSAxel Dörfler }
35418d3e65eSAxel Dörfler 
35518d3e65eSAxel Dörfler 
35618d3e65eSAxel Dörfler int64
35718d3e65eSAxel Dörfler DataHistory::MinimumValue() const
35818d3e65eSAxel Dörfler {
35951591198SAxel Dörfler 	if (fScale != NULL)
36051591198SAxel Dörfler 		return fScale->MinimumValue();
36151591198SAxel Dörfler 
36218d3e65eSAxel Dörfler 	return fMinimumValue;
36318d3e65eSAxel Dörfler }
36418d3e65eSAxel Dörfler 
36518d3e65eSAxel Dörfler 
36618d3e65eSAxel Dörfler bigtime_t
36718d3e65eSAxel Dörfler DataHistory::Start() const
36818d3e65eSAxel Dörfler {
36918d3e65eSAxel Dörfler 	if (fBuffer.CountItems() == 0)
37018d3e65eSAxel Dörfler 		return 0;
37118d3e65eSAxel Dörfler 
37218d3e65eSAxel Dörfler 	return fBuffer.ItemAt(0)->time;
37318d3e65eSAxel Dörfler }
37418d3e65eSAxel Dörfler 
37518d3e65eSAxel Dörfler 
37618d3e65eSAxel Dörfler bigtime_t
37718d3e65eSAxel Dörfler DataHistory::End() const
37818d3e65eSAxel Dörfler {
37918d3e65eSAxel Dörfler 	if (fBuffer.CountItems() == 0)
38018d3e65eSAxel Dörfler 		return 0;
38118d3e65eSAxel Dörfler 
38218d3e65eSAxel Dörfler 	return fBuffer.ItemAt(fBuffer.CountItems() - 1)->time;
38318d3e65eSAxel Dörfler }
38418d3e65eSAxel Dörfler 
38518d3e65eSAxel Dörfler 
38618d3e65eSAxel Dörfler void
38718d3e65eSAxel Dörfler DataHistory::SetRefreshInterval(bigtime_t interval)
38818d3e65eSAxel Dörfler {
38918d3e65eSAxel Dörfler 	// TODO: adjust buffer size
39018d3e65eSAxel Dörfler }
39118d3e65eSAxel Dörfler 
39218d3e65eSAxel Dörfler 
39351591198SAxel Dörfler void
39451591198SAxel Dörfler DataHistory::SetScale(Scale* scale)
39551591198SAxel Dörfler {
39651591198SAxel Dörfler 	fScale = scale;
39751591198SAxel Dörfler }
39851591198SAxel Dörfler 
39951591198SAxel Dörfler 
40018d3e65eSAxel Dörfler //	#pragma mark -
40118d3e65eSAxel Dörfler 
40218d3e65eSAxel Dörfler 
403dc1ffc79SFrançois Revol #ifdef __HAIKU__
404065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::HistoryLayoutItem(ActivityView* parent)
405065e8de0SAxel Dörfler 	:
406065e8de0SAxel Dörfler 	fParent(parent),
407065e8de0SAxel Dörfler 	fFrame()
408065e8de0SAxel Dörfler {
409065e8de0SAxel Dörfler }
410065e8de0SAxel Dörfler 
411065e8de0SAxel Dörfler 
412065e8de0SAxel Dörfler bool
413065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::IsVisible()
414065e8de0SAxel Dörfler {
415065e8de0SAxel Dörfler 	return !fParent->IsHidden(fParent);
416065e8de0SAxel Dörfler }
417065e8de0SAxel Dörfler 
418065e8de0SAxel Dörfler 
419065e8de0SAxel Dörfler void
420065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::SetVisible(bool visible)
421065e8de0SAxel Dörfler {
422065e8de0SAxel Dörfler 	// not allowed
423065e8de0SAxel Dörfler }
424065e8de0SAxel Dörfler 
425065e8de0SAxel Dörfler 
426065e8de0SAxel Dörfler BRect
427065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::Frame()
428065e8de0SAxel Dörfler {
429065e8de0SAxel Dörfler 	return fFrame;
430065e8de0SAxel Dörfler }
431065e8de0SAxel Dörfler 
432065e8de0SAxel Dörfler 
433065e8de0SAxel Dörfler void
434065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::SetFrame(BRect frame)
435065e8de0SAxel Dörfler {
436065e8de0SAxel Dörfler 	fFrame = frame;
437065e8de0SAxel Dörfler 	fParent->_UpdateFrame();
438065e8de0SAxel Dörfler }
439065e8de0SAxel Dörfler 
440065e8de0SAxel Dörfler 
441065e8de0SAxel Dörfler BView*
442065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::View()
443065e8de0SAxel Dörfler {
444065e8de0SAxel Dörfler 	return fParent;
445065e8de0SAxel Dörfler }
446065e8de0SAxel Dörfler 
447065e8de0SAxel Dörfler 
448065e8de0SAxel Dörfler BSize
449065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::BasePreferredSize()
450065e8de0SAxel Dörfler {
451065e8de0SAxel Dörfler 	BSize size(BaseMaxSize());
452065e8de0SAxel Dörfler 	return size;
453065e8de0SAxel Dörfler }
454065e8de0SAxel Dörfler 
455065e8de0SAxel Dörfler 
456065e8de0SAxel Dörfler //	#pragma mark -
457065e8de0SAxel Dörfler 
458065e8de0SAxel Dörfler 
459065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::LegendLayoutItem(ActivityView* parent)
460065e8de0SAxel Dörfler 	:
461065e8de0SAxel Dörfler 	fParent(parent),
462065e8de0SAxel Dörfler 	fFrame()
463065e8de0SAxel Dörfler {
464065e8de0SAxel Dörfler }
465065e8de0SAxel Dörfler 
466065e8de0SAxel Dörfler 
467065e8de0SAxel Dörfler bool
468065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::IsVisible()
469065e8de0SAxel Dörfler {
470065e8de0SAxel Dörfler 	return !fParent->IsHidden(fParent);
471065e8de0SAxel Dörfler }
472065e8de0SAxel Dörfler 
473065e8de0SAxel Dörfler 
474065e8de0SAxel Dörfler void
475065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::SetVisible(bool visible)
476065e8de0SAxel Dörfler {
477065e8de0SAxel Dörfler 	// not allowed
478065e8de0SAxel Dörfler }
479065e8de0SAxel Dörfler 
480065e8de0SAxel Dörfler 
481065e8de0SAxel Dörfler BRect
482065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::Frame()
483065e8de0SAxel Dörfler {
484065e8de0SAxel Dörfler 	return fFrame;
485065e8de0SAxel Dörfler }
486065e8de0SAxel Dörfler 
487065e8de0SAxel Dörfler 
488065e8de0SAxel Dörfler void
489065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::SetFrame(BRect frame)
490065e8de0SAxel Dörfler {
491065e8de0SAxel Dörfler 	fFrame = frame;
492065e8de0SAxel Dörfler 	fParent->_UpdateFrame();
493065e8de0SAxel Dörfler }
494065e8de0SAxel Dörfler 
495065e8de0SAxel Dörfler 
496065e8de0SAxel Dörfler BView*
497065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::View()
498065e8de0SAxel Dörfler {
499065e8de0SAxel Dörfler 	return fParent;
500065e8de0SAxel Dörfler }
501065e8de0SAxel Dörfler 
502065e8de0SAxel Dörfler 
503065e8de0SAxel Dörfler BSize
504065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::BaseMinSize()
505065e8de0SAxel Dörfler {
506065e8de0SAxel Dörfler 	// TODO: Cache the info. Might be too expensive for this call.
507065e8de0SAxel Dörfler 	BSize size;
508065e8de0SAxel Dörfler 	size.width = 80;
509065e8de0SAxel Dörfler 	size.height = fParent->_LegendHeight();
510065e8de0SAxel Dörfler 
511065e8de0SAxel Dörfler 	return size;
512065e8de0SAxel Dörfler }
513065e8de0SAxel Dörfler 
514065e8de0SAxel Dörfler 
515065e8de0SAxel Dörfler BSize
516065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::BaseMaxSize()
517065e8de0SAxel Dörfler {
518065e8de0SAxel Dörfler 	BSize size(BaseMinSize());
519065e8de0SAxel Dörfler 	size.width = B_SIZE_UNLIMITED;
520065e8de0SAxel Dörfler 	return size;
521065e8de0SAxel Dörfler }
522065e8de0SAxel Dörfler 
523065e8de0SAxel Dörfler 
524065e8de0SAxel Dörfler BSize
525065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::BasePreferredSize()
526065e8de0SAxel Dörfler {
527065e8de0SAxel Dörfler 	BSize size(BaseMinSize());
528065e8de0SAxel Dörfler 	return size;
529065e8de0SAxel Dörfler }
530065e8de0SAxel Dörfler 
531065e8de0SAxel Dörfler 
532065e8de0SAxel Dörfler BAlignment
533065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::BaseAlignment()
534065e8de0SAxel Dörfler {
535065e8de0SAxel Dörfler 	return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
536065e8de0SAxel Dörfler }
537dc1ffc79SFrançois Revol #endif
538065e8de0SAxel Dörfler 
539065e8de0SAxel Dörfler 
540065e8de0SAxel Dörfler //	#pragma mark -
541065e8de0SAxel Dörfler 
542065e8de0SAxel Dörfler 
54318d3e65eSAxel Dörfler ActivityView::ActivityView(BRect frame, const char* name,
5443a4a2141SAxel Dörfler 		const BMessage* settings, uint32 resizingMode)
54518d3e65eSAxel Dörfler 	: BView(frame, name, resizingMode,
546d4216445SAxel Dörfler 		B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS),
547d4216445SAxel Dörfler 	fSourcesLock("data sources")
54818d3e65eSAxel Dörfler {
5493a4a2141SAxel Dörfler 	_Init(settings);
5503a4a2141SAxel Dörfler 
5513a4a2141SAxel Dörfler 	BRect rect(Bounds());
5523a4a2141SAxel Dörfler 	rect.top = rect.bottom - 7;
5533a4a2141SAxel Dörfler 	rect.left = rect.right - 7;
5543a4a2141SAxel Dörfler 	BDragger* dragger = new BDragger(rect, this,
5553a4a2141SAxel Dörfler 		B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
5563a4a2141SAxel Dörfler 	AddChild(dragger);
5573a4a2141SAxel Dörfler }
5583a4a2141SAxel Dörfler 
5593a4a2141SAxel Dörfler 
5603a4a2141SAxel Dörfler ActivityView::ActivityView(const char* name, const BMessage* settings)
561cbd4bc95SFrançois Revol #ifdef __HAIKU__
562d4216445SAxel Dörfler 	: BView(name, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS),
563cbd4bc95SFrançois Revol #else
564d4216445SAxel Dörfler 	: BView(BRect(0, 0, 300, 200), name, B_FOLLOW_NONE,
565d4216445SAxel Dörfler 		B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS),
566cbd4bc95SFrançois Revol #endif
567d4216445SAxel Dörfler 	fSourcesLock("data sources")
5683a4a2141SAxel Dörfler {
56979cbd226SFrançois Revol 	SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
5709c89c450SAxel Dörfler 
5713a4a2141SAxel Dörfler 	_Init(settings);
57218d3e65eSAxel Dörfler 
57318d3e65eSAxel Dörfler 	BRect rect(Bounds());
57418d3e65eSAxel Dörfler 	rect.top = rect.bottom - 7;
57518d3e65eSAxel Dörfler 	rect.left = rect.right - 7;
57618d3e65eSAxel Dörfler 	BDragger* dragger = new BDragger(rect, this,
57718d3e65eSAxel Dörfler 		B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
57818d3e65eSAxel Dörfler 	AddChild(dragger);
57918d3e65eSAxel Dörfler }
58018d3e65eSAxel Dörfler 
58118d3e65eSAxel Dörfler 
58218d3e65eSAxel Dörfler ActivityView::ActivityView(BMessage* archive)
58318d3e65eSAxel Dörfler 	: BView(archive)
58418d3e65eSAxel Dörfler {
58518d3e65eSAxel Dörfler 	_Init(archive);
58618d3e65eSAxel Dörfler }
58718d3e65eSAxel Dörfler 
58818d3e65eSAxel Dörfler 
58918d3e65eSAxel Dörfler ActivityView::~ActivityView()
59018d3e65eSAxel Dörfler {
5913a4a2141SAxel Dörfler 	delete fOffscreen;
59274158bb4SFrançois Revol 	delete fSystemInfoHandler;
59318d3e65eSAxel Dörfler }
59418d3e65eSAxel Dörfler 
59518d3e65eSAxel Dörfler 
59618d3e65eSAxel Dörfler void
59718d3e65eSAxel Dörfler ActivityView::_Init(const BMessage* settings)
59818d3e65eSAxel Dörfler {
5999c89c450SAxel Dörfler 	fHistoryBackgroundColor = (rgb_color){255, 255, 240};
6009c89c450SAxel Dörfler 	fLegendBackgroundColor = LowColor();
6019c89c450SAxel Dörfler 		// the low color is restored by the BView unarchiving
6023a4a2141SAxel Dörfler 	fOffscreen = NULL;
603dc1ffc79SFrançois Revol #ifdef __HAIKU__
604065e8de0SAxel Dörfler 	fHistoryLayoutItem = NULL;
605065e8de0SAxel Dörfler 	fLegendLayoutItem = NULL;
606dc1ffc79SFrançois Revol #endif
6073a4a2141SAxel Dörfler 	SetViewColor(B_TRANSPARENT_COLOR);
60818d3e65eSAxel Dörfler 
60918d3e65eSAxel Dörfler 	fLastRefresh = 0;
61018d3e65eSAxel Dörfler 	fDrawResolution = 1;
61151591198SAxel Dörfler 	fZooming = false;
61218d3e65eSAxel Dörfler 
61374158bb4SFrançois Revol 	fSystemInfoHandler = new SystemInfoHandler;
61474158bb4SFrançois Revol 
6153a4a2141SAxel Dörfler 	if (settings == NULL
616eee6f40bSAlexandre Deckner 		|| settings->FindInt64("refresh interval", &fRefreshInterval) != B_OK)
617eee6f40bSAlexandre Deckner 		fRefreshInterval = kInitialRefreshInterval;
618eee6f40bSAlexandre Deckner 
619eee6f40bSAlexandre Deckner 	if (settings == NULL
6203a4a2141SAxel Dörfler 		|| settings->FindBool("show legend", &fShowLegend) != B_OK)
6213a4a2141SAxel Dörfler 		fShowLegend = true;
6223a4a2141SAxel Dörfler 
62351591198SAxel Dörfler 	if (settings == NULL)
6243a4a2141SAxel Dörfler 		return;
6253a4a2141SAxel Dörfler 
6269c89c450SAxel Dörfler 	ssize_t colorLength;
62779cbd226SFrançois Revol 	rgb_color *color;
6289c89c450SAxel Dörfler 	if (settings->FindData("history background color", B_RGB_COLOR_TYPE,
6299c89c450SAxel Dörfler 			(const void **)&color, &colorLength) == B_OK
6309c89c450SAxel Dörfler 		&& colorLength == sizeof(rgb_color))
6319c89c450SAxel Dörfler 		fHistoryBackgroundColor = *color;
63279cbd226SFrançois Revol 
6333a4a2141SAxel Dörfler 	const char* name;
6343a4a2141SAxel Dörfler 	for (int32 i = 0; settings->FindString("source", i, &name) == B_OK; i++) {
6351201d52eSAxel Dörfler 		AddDataSource(DataSource::FindSource(name), settings);
6363a4a2141SAxel Dörfler 	}
63718d3e65eSAxel Dörfler }
63818d3e65eSAxel Dörfler 
63918d3e65eSAxel Dörfler 
64018d3e65eSAxel Dörfler status_t
64118d3e65eSAxel Dörfler ActivityView::Archive(BMessage* into, bool deep) const
64218d3e65eSAxel Dörfler {
64318d3e65eSAxel Dörfler 	status_t status;
64418d3e65eSAxel Dörfler 
64518d3e65eSAxel Dörfler 	status = BView::Archive(into, deep);
64618d3e65eSAxel Dörfler 	if (status < B_OK)
64718d3e65eSAxel Dörfler 		return status;
64818d3e65eSAxel Dörfler 
64918d3e65eSAxel Dörfler 	status = into->AddString("add_on", kSignature);
65018d3e65eSAxel Dörfler 	if (status < B_OK)
65118d3e65eSAxel Dörfler 		return status;
65218d3e65eSAxel Dörfler 
65318d3e65eSAxel Dörfler 	status = SaveState(*into);
65418d3e65eSAxel Dörfler 	if (status < B_OK)
65518d3e65eSAxel Dörfler 		return status;
65618d3e65eSAxel Dörfler 
65718d3e65eSAxel Dörfler 	return B_OK;
65818d3e65eSAxel Dörfler }
65918d3e65eSAxel Dörfler 
66018d3e65eSAxel Dörfler 
66118d3e65eSAxel Dörfler BArchivable*
66218d3e65eSAxel Dörfler ActivityView::Instantiate(BMessage* archive)
66318d3e65eSAxel Dörfler {
66418d3e65eSAxel Dörfler 	if (!validate_instantiation(archive, "ActivityView"))
66518d3e65eSAxel Dörfler 		return NULL;
66618d3e65eSAxel Dörfler 
66718d3e65eSAxel Dörfler 	return new ActivityView(archive);
66818d3e65eSAxel Dörfler }
66918d3e65eSAxel Dörfler 
67018d3e65eSAxel Dörfler 
67118d3e65eSAxel Dörfler status_t
67218d3e65eSAxel Dörfler ActivityView::SaveState(BMessage& state) const
67318d3e65eSAxel Dörfler {
6743a4a2141SAxel Dörfler 	status_t status = state.AddBool("show legend", fShowLegend);
6753a4a2141SAxel Dörfler 	if (status != B_OK)
6763a4a2141SAxel Dörfler 		return status;
6773a4a2141SAxel Dörfler 
678eee6f40bSAlexandre Deckner 	status = state.AddInt64("refresh interval", fRefreshInterval);
679eee6f40bSAlexandre Deckner 	if (status != B_OK)
680eee6f40bSAlexandre Deckner 		return status;
681eee6f40bSAlexandre Deckner 
6829c89c450SAxel Dörfler 	status = state.AddData("history background color", B_RGB_COLOR_TYPE,
6839c89c450SAxel Dörfler 		&fHistoryBackgroundColor, sizeof(rgb_color));
68479cbd226SFrançois Revol 	if (status != B_OK)
68579cbd226SFrançois Revol 		return status;
68679cbd226SFrançois Revol 
6873a4a2141SAxel Dörfler 	for (int32 i = 0; i < fSources.CountItems(); i++) {
6883a4a2141SAxel Dörfler 		DataSource* source = fSources.ItemAt(i);
6893a4a2141SAxel Dörfler 
6903a4a2141SAxel Dörfler 		if (!source->PerCPU() || source->CPU() == 0)
6913a4a2141SAxel Dörfler 			status = state.AddString("source", source->Name());
6923a4a2141SAxel Dörfler 		if (status != B_OK)
6933a4a2141SAxel Dörfler 			return status;
6943a4a2141SAxel Dörfler 
6959c89c450SAxel Dörfler 		BString name = source->Name();
6969c89c450SAxel Dörfler 		name << " color";
6979c89c450SAxel Dörfler 		rgb_color color = source->Color();
6989c89c450SAxel Dörfler 		state.AddData(name.String(), B_RGB_COLOR_TYPE, &color,
6999c89c450SAxel Dörfler 			sizeof(rgb_color));
7003a4a2141SAxel Dörfler 	}
7013a4a2141SAxel Dörfler 	return B_OK;
70218d3e65eSAxel Dörfler }
70318d3e65eSAxel Dörfler 
70418d3e65eSAxel Dörfler 
70551591198SAxel Dörfler Scale*
70651591198SAxel Dörfler ActivityView::_ScaleFor(scale_type type)
70751591198SAxel Dörfler {
70851591198SAxel Dörfler 	if (type == kNoScale)
70951591198SAxel Dörfler 		return NULL;
71051591198SAxel Dörfler 
71151591198SAxel Dörfler 	std::map<scale_type, ::Scale*>::iterator iterator = fScales.find(type);
71251591198SAxel Dörfler 	if (iterator != fScales.end())
71351591198SAxel Dörfler 		return iterator->second;
71451591198SAxel Dörfler 
71551591198SAxel Dörfler 	// add new scale
71651591198SAxel Dörfler 	::Scale* scale = new ::Scale(type);
71751591198SAxel Dörfler 	fScales[type] = scale;
71851591198SAxel Dörfler 
71951591198SAxel Dörfler 	return scale;
72051591198SAxel Dörfler }
72151591198SAxel Dörfler 
72251591198SAxel Dörfler 
723dc1ffc79SFrançois Revol #ifdef __HAIKU__
724065e8de0SAxel Dörfler BLayoutItem*
725065e8de0SAxel Dörfler ActivityView::CreateHistoryLayoutItem()
726065e8de0SAxel Dörfler {
727065e8de0SAxel Dörfler 	if (fHistoryLayoutItem == NULL)
728065e8de0SAxel Dörfler 		fHistoryLayoutItem = new HistoryLayoutItem(this);
729065e8de0SAxel Dörfler 
730065e8de0SAxel Dörfler 	return fHistoryLayoutItem;
731065e8de0SAxel Dörfler }
732065e8de0SAxel Dörfler 
733065e8de0SAxel Dörfler 
734065e8de0SAxel Dörfler BLayoutItem*
735065e8de0SAxel Dörfler ActivityView::CreateLegendLayoutItem()
736065e8de0SAxel Dörfler {
737065e8de0SAxel Dörfler 	if (fLegendLayoutItem == NULL)
738065e8de0SAxel Dörfler 		fLegendLayoutItem = new LegendLayoutItem(this);
739065e8de0SAxel Dörfler 
740065e8de0SAxel Dörfler 	return fLegendLayoutItem;
741065e8de0SAxel Dörfler }
742dc1ffc79SFrançois Revol #endif
743065e8de0SAxel Dörfler 
7449c89c450SAxel Dörfler 
74518d3e65eSAxel Dörfler DataSource*
7463a4a2141SAxel Dörfler ActivityView::FindDataSource(const DataSource* search)
74718d3e65eSAxel Dörfler {
748d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
749d4216445SAxel Dörfler 
75018d3e65eSAxel Dörfler 	for (int32 i = fSources.CountItems(); i-- > 0;) {
75118d3e65eSAxel Dörfler 		DataSource* source = fSources.ItemAt(i);
7523a4a2141SAxel Dörfler 		if (!strcmp(source->Name(), search->Name()))
75318d3e65eSAxel Dörfler 			return source;
75418d3e65eSAxel Dörfler 	}
75518d3e65eSAxel Dörfler 
75618d3e65eSAxel Dörfler 	return NULL;
75718d3e65eSAxel Dörfler }
75818d3e65eSAxel Dörfler 
75918d3e65eSAxel Dörfler 
76018d3e65eSAxel Dörfler status_t
7619c89c450SAxel Dörfler ActivityView::AddDataSource(const DataSource* source, const BMessage* state)
76218d3e65eSAxel Dörfler {
7633a4a2141SAxel Dörfler 	if (source == NULL)
7643a4a2141SAxel Dörfler 		return B_BAD_VALUE;
7653a4a2141SAxel Dörfler 
766d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
767d4216445SAxel Dörfler 
7688e26f387SAxel Dörfler 	// Search for the correct insert spot to maintain the order of the sources
7693a4a2141SAxel Dörfler 	int32 insert = DataSource::IndexOf(source);
7703a4a2141SAxel Dörfler 	for (int32 i = 0; i < fSources.CountItems() && i < insert; i++) {
7713a4a2141SAxel Dörfler 		DataSource* before = fSources.ItemAt(i);
7723a4a2141SAxel Dörfler 		if (DataSource::IndexOf(before) > insert) {
7733a4a2141SAxel Dörfler 			insert = i;
7743a4a2141SAxel Dörfler 			break;
7753a4a2141SAxel Dörfler 		}
7763a4a2141SAxel Dörfler 	}
7773a4a2141SAxel Dörfler 	if (insert > fSources.CountItems())
7783a4a2141SAxel Dörfler 		insert = fSources.CountItems();
7793a4a2141SAxel Dörfler 
7808e26f387SAxel Dörfler 	// Generate DataHistory and ViewHistory objects for the source
7818e26f387SAxel Dörfler 	// (one might need one history per CPU)
7828e26f387SAxel Dörfler 
7833a4a2141SAxel Dörfler 	uint32 count = 1;
7843a4a2141SAxel Dörfler 	if (source->PerCPU()) {
7853a4a2141SAxel Dörfler 		SystemInfo info;
7863a4a2141SAxel Dörfler 		count = info.CPUCount();
7873a4a2141SAxel Dörfler 	}
7883a4a2141SAxel Dörfler 
7893a4a2141SAxel Dörfler 	for (uint32 i = 0; i < count; i++) {
79018d3e65eSAxel Dörfler 		DataHistory* values = new(std::nothrow) DataHistory(10 * 60000000LL,
7911bb87bd0SAxel Dörfler 			RefreshInterval());
7928e26f387SAxel Dörfler 		ListAddDeleter<DataHistory> valuesDeleter(fValues, values, insert);
7933a4a2141SAxel Dörfler 
7948e26f387SAxel Dörfler 		ViewHistory* viewValues = new(std::nothrow) ViewHistory;
7958e26f387SAxel Dörfler 		ListAddDeleter<ViewHistory> viewValuesDeleter(fViewValues, viewValues,
7968e26f387SAxel Dörfler 			insert);
7978e26f387SAxel Dörfler 
7988e26f387SAxel Dörfler 		if (valuesDeleter.Failed() || viewValuesDeleter.Failed())
79918d3e65eSAxel Dörfler 			return B_NO_MEMORY;
80018d3e65eSAxel Dörfler 
80151591198SAxel Dörfler 		values->SetScale(_ScaleFor(source->ScaleType()));
80251591198SAxel Dörfler 
8033a4a2141SAxel Dörfler 		DataSource* copy;
8043a4a2141SAxel Dörfler 		if (source->PerCPU())
8053a4a2141SAxel Dörfler 			copy = source->CopyForCPU(i);
8063a4a2141SAxel Dörfler 		else
8073a4a2141SAxel Dörfler 			copy = source->Copy();
8083a4a2141SAxel Dörfler 
8098e26f387SAxel Dörfler 		ListAddDeleter<DataSource> sourceDeleter(fSources, copy, insert);
8108e26f387SAxel Dörfler 		if (sourceDeleter.Failed())
8118e26f387SAxel Dörfler 			return B_NO_MEMORY;
8128e26f387SAxel Dörfler 
8139c89c450SAxel Dörfler 		BString colorName = source->Name();
8149c89c450SAxel Dörfler 		colorName << " color";
8159c89c450SAxel Dörfler 		if (state != NULL) {
8169c89c450SAxel Dörfler 			const rgb_color* color = NULL;
8179c89c450SAxel Dörfler 			ssize_t colorLength;
8189c89c450SAxel Dörfler 			if (state->FindData(colorName.String(), B_RGB_COLOR_TYPE, i,
8199c89c450SAxel Dörfler 					(const void**)&color, &colorLength) == B_OK
8209c89c450SAxel Dörfler 				&& colorLength == sizeof(rgb_color))
8219c89c450SAxel Dörfler 				copy->SetColor(*color);
8229c89c450SAxel Dörfler 		}
8239c89c450SAxel Dörfler 
8248e26f387SAxel Dörfler 		valuesDeleter.Detach();
8258e26f387SAxel Dörfler 		viewValuesDeleter.Detach();
8268e26f387SAxel Dörfler 		sourceDeleter.Detach();
8273a4a2141SAxel Dörfler 	}
82818d3e65eSAxel Dörfler 
829dc1ffc79SFrançois Revol #ifdef __HAIKU__
830065e8de0SAxel Dörfler 	InvalidateLayout();
831dc1ffc79SFrançois Revol #endif
83218d3e65eSAxel Dörfler 	return B_OK;
83318d3e65eSAxel Dörfler }
83418d3e65eSAxel Dörfler 
83518d3e65eSAxel Dörfler 
83618d3e65eSAxel Dörfler status_t
8373a4a2141SAxel Dörfler ActivityView::RemoveDataSource(const DataSource* remove)
83818d3e65eSAxel Dörfler {
839065e8de0SAxel Dörfler 	bool removed = false;
840065e8de0SAxel Dörfler 
841d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
842d4216445SAxel Dörfler 
8433a4a2141SAxel Dörfler 	while (true) {
8443a4a2141SAxel Dörfler 		DataSource* source = FindDataSource(remove);
845065e8de0SAxel Dörfler 		if (source == NULL) {
846065e8de0SAxel Dörfler 			if (removed)
847065e8de0SAxel Dörfler 				break;
848065e8de0SAxel Dörfler 			return B_ENTRY_NOT_FOUND;
849065e8de0SAxel Dörfler 		}
8503a4a2141SAxel Dörfler 
85118d3e65eSAxel Dörfler 		int32 index = fSources.IndexOf(source);
85218d3e65eSAxel Dörfler 		if (index < 0)
85318d3e65eSAxel Dörfler 			return B_ENTRY_NOT_FOUND;
85418d3e65eSAxel Dörfler 
85518d3e65eSAxel Dörfler 		fSources.RemoveItemAt(index);
85618d3e65eSAxel Dörfler 		delete source;
85718d3e65eSAxel Dörfler 		DataHistory* values = fValues.RemoveItemAt(index);
85818d3e65eSAxel Dörfler 		delete values;
859065e8de0SAxel Dörfler 		removed = true;
8603a4a2141SAxel Dörfler 	}
86118d3e65eSAxel Dörfler 
862dc1ffc79SFrançois Revol #ifdef __HAIKU__
863065e8de0SAxel Dörfler 	InvalidateLayout();
864dc1ffc79SFrançois Revol #endif
86518d3e65eSAxel Dörfler 	return B_OK;
86618d3e65eSAxel Dörfler }
86718d3e65eSAxel Dörfler 
86818d3e65eSAxel Dörfler 
86918d3e65eSAxel Dörfler void
87018d3e65eSAxel Dörfler ActivityView::RemoveAllDataSources()
87118d3e65eSAxel Dörfler {
872d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
873d4216445SAxel Dörfler 
87418d3e65eSAxel Dörfler 	fSources.MakeEmpty();
87518d3e65eSAxel Dörfler 	fValues.MakeEmpty();
87618d3e65eSAxel Dörfler }
87718d3e65eSAxel Dörfler 
87818d3e65eSAxel Dörfler 
87918d3e65eSAxel Dörfler void
88018d3e65eSAxel Dörfler ActivityView::AttachedToWindow()
88118d3e65eSAxel Dörfler {
88274158bb4SFrançois Revol 	Looper()->AddHandler(fSystemInfoHandler);
8836f6ba875SAxel Dörfler 	fSystemInfoHandler->StartWatching();
8846f6ba875SAxel Dörfler 
885d4216445SAxel Dörfler 	fRefreshSem = create_sem(0, "refresh sem");
886d4216445SAxel Dörfler 	fRefreshThread = spawn_thread(&_RefreshThread, "source refresh",
8878e26f387SAxel Dörfler 		B_URGENT_DISPLAY_PRIORITY, this);
888d4216445SAxel Dörfler 	resume_thread(fRefreshThread);
8893a4a2141SAxel Dörfler 
8903a4a2141SAxel Dörfler 	FrameResized(Bounds().Width(), Bounds().Height());
89118d3e65eSAxel Dörfler }
89218d3e65eSAxel Dörfler 
89318d3e65eSAxel Dörfler 
89418d3e65eSAxel Dörfler void
89518d3e65eSAxel Dörfler ActivityView::DetachedFromWindow()
89618d3e65eSAxel Dörfler {
8976f6ba875SAxel Dörfler 	fSystemInfoHandler->StopWatching();
89874158bb4SFrançois Revol 	Looper()->RemoveHandler(fSystemInfoHandler);
8996f6ba875SAxel Dörfler 
900d4216445SAxel Dörfler 	delete_sem(fRefreshSem);
901d4216445SAxel Dörfler 	wait_for_thread(fRefreshThread, NULL);
90218d3e65eSAxel Dörfler }
90318d3e65eSAxel Dörfler 
90418d3e65eSAxel Dörfler 
905cbd4bc95SFrançois Revol #ifdef __HAIKU__
9063a4a2141SAxel Dörfler BSize
9073a4a2141SAxel Dörfler ActivityView::MinSize()
9083a4a2141SAxel Dörfler {
9093a4a2141SAxel Dörfler 	BSize size(32, 32);
9103a4a2141SAxel Dörfler 	if (fShowLegend)
9119c89c450SAxel Dörfler 		size.height = _LegendHeight();
9123a4a2141SAxel Dörfler 
9133a4a2141SAxel Dörfler 	return size;
9143a4a2141SAxel Dörfler }
915cbd4bc95SFrançois Revol #endif
9163a4a2141SAxel Dörfler 
9173a4a2141SAxel Dörfler 
91818d3e65eSAxel Dörfler void
91918d3e65eSAxel Dörfler ActivityView::FrameResized(float /*width*/, float /*height*/)
92018d3e65eSAxel Dörfler {
9213a4a2141SAxel Dörfler 	_UpdateOffscreenBitmap();
9223a4a2141SAxel Dörfler }
9233a4a2141SAxel Dörfler 
9243a4a2141SAxel Dörfler 
9253a4a2141SAxel Dörfler void
9269c89c450SAxel Dörfler ActivityView::_UpdateOffscreenBitmap()
9273a4a2141SAxel Dörfler {
9283a4a2141SAxel Dörfler 	BRect frame = _HistoryFrame();
929ed1b2753SStephan Aßmus 	frame.OffsetTo(B_ORIGIN);
930ed1b2753SStephan Aßmus 
9319c89c450SAxel Dörfler 	if (fOffscreen != NULL && frame == fOffscreen->Bounds())
9323a4a2141SAxel Dörfler 		return;
9333a4a2141SAxel Dörfler 
9343a4a2141SAxel Dörfler 	delete fOffscreen;
9353a4a2141SAxel Dörfler 
9363a4a2141SAxel Dörfler 	// create offscreen bitmap
9373a4a2141SAxel Dörfler 
9383a4a2141SAxel Dörfler 	fOffscreen = new(std::nothrow) BBitmap(frame, B_BITMAP_ACCEPTS_VIEWS,
9393a4a2141SAxel Dörfler 		B_RGB32);
9403a4a2141SAxel Dörfler 	if (fOffscreen == NULL || fOffscreen->InitCheck() != B_OK) {
9413a4a2141SAxel Dörfler 		delete fOffscreen;
9423a4a2141SAxel Dörfler 		fOffscreen = NULL;
9433a4a2141SAxel Dörfler 		return;
9443a4a2141SAxel Dörfler 	}
9453a4a2141SAxel Dörfler 
9463a4a2141SAxel Dörfler 	BView* view = new BView(frame, NULL, B_FOLLOW_NONE, B_SUBPIXEL_PRECISE);
9479c89c450SAxel Dörfler 	view->SetViewColor(fHistoryBackgroundColor);
9483a4a2141SAxel Dörfler 	view->SetLowColor(view->ViewColor());
9493a4a2141SAxel Dörfler 	fOffscreen->AddChild(view);
95018d3e65eSAxel Dörfler }
95118d3e65eSAxel Dörfler 
95218d3e65eSAxel Dörfler 
9539c89c450SAxel Dörfler BView*
9549c89c450SAxel Dörfler ActivityView::_OffscreenView()
9559c89c450SAxel Dörfler {
9569c89c450SAxel Dörfler 	if (fOffscreen == NULL)
9579c89c450SAxel Dörfler 		return NULL;
9589c89c450SAxel Dörfler 
9599c89c450SAxel Dörfler 	return fOffscreen->ChildAt(0);
9609c89c450SAxel Dörfler }
9619c89c450SAxel Dörfler 
9629c89c450SAxel Dörfler 
96318d3e65eSAxel Dörfler void
96418d3e65eSAxel Dörfler ActivityView::MouseDown(BPoint where)
96518d3e65eSAxel Dörfler {
96651591198SAxel Dörfler 	int32 buttons = B_SECONDARY_MOUSE_BUTTON;
96751591198SAxel Dörfler 	if (Looper() != NULL && Looper()->CurrentMessage() != NULL)
96818d3e65eSAxel Dörfler 		Looper()->CurrentMessage()->FindInt32("buttons", &buttons);
96951591198SAxel Dörfler 
97051591198SAxel Dörfler 	if (buttons == B_PRIMARY_MOUSE_BUTTON) {
97151591198SAxel Dörfler 		fZoomPoint = where;
97251591198SAxel Dörfler 		fOriginalResolution = fDrawResolution;
97351591198SAxel Dörfler 		fZooming = true;
9748e26f387SAxel Dörfler 		SetMouseEventMask(B_POINTER_EVENTS);
97551591198SAxel Dörfler 		return;
97618d3e65eSAxel Dörfler 	}
97718d3e65eSAxel Dörfler 
97818d3e65eSAxel Dörfler 	BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING, false, false);
97918d3e65eSAxel Dörfler 	menu->SetFont(be_plain_font);
9803a4a2141SAxel Dörfler 
981*7974d3dcSStephan Aßmus 	BMenu* additionalMenu = new BMenu("Additional items");
982dc1ffc79SFrançois Revol 	additionalMenu->SetFont(be_plain_font);
983dc1ffc79SFrançois Revol 
9843a4a2141SAxel Dörfler 	SystemInfo info;
98518d3e65eSAxel Dörfler 	BMenuItem* item;
98618d3e65eSAxel Dörfler 
98718d3e65eSAxel Dörfler 	for (int32 i = 0; i < DataSource::CountSources(); i++) {
98818d3e65eSAxel Dörfler 		const DataSource* source = DataSource::SourceAt(i);
98918d3e65eSAxel Dörfler 
9903a4a2141SAxel Dörfler 		if (source->MultiCPUOnly() && info.CPUCount() == 1)
9913a4a2141SAxel Dörfler 			continue;
9923a4a2141SAxel Dörfler 
99318d3e65eSAxel Dörfler 		BMessage* message = new BMessage(kMsgToggleDataSource);
99418d3e65eSAxel Dörfler 		message->AddInt32("index", i);
99518d3e65eSAxel Dörfler 
9963a4a2141SAxel Dörfler 		item = new BMenuItem(source->Name(), message);
9973a4a2141SAxel Dörfler 		if (FindDataSource(source))
99818d3e65eSAxel Dörfler 			item->SetMarked(true);
99918d3e65eSAxel Dörfler 
100043eda1cdSAxel Dörfler 		if (source->Primary())
100118d3e65eSAxel Dörfler 			menu->AddItem(item);
100243eda1cdSAxel Dörfler 		else
100343eda1cdSAxel Dörfler 			additionalMenu->AddItem(item);
100418d3e65eSAxel Dörfler 	}
100518d3e65eSAxel Dörfler 
100643eda1cdSAxel Dörfler 	menu->AddItem(new BMenuItem(additionalMenu));
10073a4a2141SAxel Dörfler 	menu->AddSeparatorItem();
1008*7974d3dcSStephan Aßmus 	menu->AddItem(new BMenuItem(fShowLegend ? "Hide legend" : "Show legend",
10093a4a2141SAxel Dörfler 		new BMessage(kMsgToggleLegend)));
10103a4a2141SAxel Dörfler 
101118d3e65eSAxel Dörfler 	menu->SetTargetForItems(this);
1012dc1ffc79SFrançois Revol 	additionalMenu->SetTargetForItems(this);
101318d3e65eSAxel Dörfler 
10143f315b26SAxel Dörfler 	ActivityWindow* window = dynamic_cast<ActivityWindow*>(Window());
10153f315b26SAxel Dörfler 	if (window != NULL && window->ActivityViewCount() > 1) {
10163f315b26SAxel Dörfler 		menu->AddSeparatorItem();
10173f315b26SAxel Dörfler 		BMessage* message = new BMessage(kMsgRemoveView);
10183f315b26SAxel Dörfler 		message->AddPointer("view", this);
1019*7974d3dcSStephan Aßmus 		menu->AddItem(item = new BMenuItem("Remove graph", message));
10203f315b26SAxel Dörfler 		item->SetTarget(window);
10213f315b26SAxel Dörfler 	}
10223f315b26SAxel Dörfler 
102318d3e65eSAxel Dörfler 	ConvertToScreen(&where);
102418d3e65eSAxel Dörfler 	menu->Go(where, true, false, true);
102518d3e65eSAxel Dörfler }
102618d3e65eSAxel Dörfler 
102718d3e65eSAxel Dörfler 
102818d3e65eSAxel Dörfler void
102951591198SAxel Dörfler ActivityView::MouseUp(BPoint where)
103051591198SAxel Dörfler {
103151591198SAxel Dörfler 	fZooming = false;
103251591198SAxel Dörfler }
103351591198SAxel Dörfler 
103451591198SAxel Dörfler 
103551591198SAxel Dörfler void
103618d3e65eSAxel Dörfler ActivityView::MouseMoved(BPoint where, uint32 transit,
103718d3e65eSAxel Dörfler 	const BMessage* dragMessage)
103818d3e65eSAxel Dörfler {
103951591198SAxel Dörfler 	if (!fZooming)
104051591198SAxel Dörfler 		return;
104151591198SAxel Dörfler 
104251591198SAxel Dörfler 	int32 shift = int32(where.x - fZoomPoint.x) / 25;
10431bb87bd0SAxel Dörfler 	int32 resolution;
104451591198SAxel Dörfler 	if (shift > 0)
10451bb87bd0SAxel Dörfler 		resolution = fOriginalResolution << shift;
104651591198SAxel Dörfler 	else
10471bb87bd0SAxel Dörfler 		resolution = fOriginalResolution >> -shift;
104851591198SAxel Dörfler 
10491bb87bd0SAxel Dörfler 	_UpdateResolution(resolution);
105018d3e65eSAxel Dörfler }
105118d3e65eSAxel Dörfler 
105218d3e65eSAxel Dörfler 
105318d3e65eSAxel Dörfler void
105418d3e65eSAxel Dörfler ActivityView::MessageReceived(BMessage* message)
105518d3e65eSAxel Dörfler {
1056c28f8ea3SFrançois Revol 	// if a color is dropped, use it as background
1057c28f8ea3SFrançois Revol 	if (message->WasDropped()) {
1058c28f8ea3SFrançois Revol 		rgb_color* color;
1059c28f8ea3SFrançois Revol 		ssize_t size;
10601201d52eSAxel Dörfler 		if (message->FindData("RGBColor", B_RGB_COLOR_TYPE, 0,
10611201d52eSAxel Dörfler 				(const void**)&color, &size) == B_OK
10629c89c450SAxel Dörfler 			&& size == sizeof(rgb_color)) {
10639c89c450SAxel Dörfler 			BPoint dropPoint = message->DropPoint();
1064c28f8ea3SFrançois Revol 			ConvertFromScreen(&dropPoint);
10659c89c450SAxel Dörfler 
1066c28f8ea3SFrançois Revol 			if (_HistoryFrame().Contains(dropPoint)) {
10679c89c450SAxel Dörfler 				fHistoryBackgroundColor = *color;
10689c89c450SAxel Dörfler 				Invalidate(_HistoryFrame());
1069c28f8ea3SFrançois Revol 			} else {
10705f2f72a2SFrançois Revol 				// check each legend color box
1071d4216445SAxel Dörfler 				BAutolock _(fSourcesLock);
1072d4216445SAxel Dörfler 
10735f2f72a2SFrançois Revol 				BRect legendFrame = _LegendFrame();
10749c89c450SAxel Dörfler 				for (int32 i = 0; i < fSources.CountItems(); i++) {
10751201d52eSAxel Dörfler 					BRect frame = _LegendColorFrameAt(legendFrame, i);
10769c89c450SAxel Dörfler 					if (frame.Contains(dropPoint)) {
10775f2f72a2SFrançois Revol 						fSources.ItemAt(i)->SetColor(*color);
10789c89c450SAxel Dörfler 						Invalidate(_HistoryFrame());
10791201d52eSAxel Dörfler 						Invalidate(frame);
10805f2f72a2SFrançois Revol 						return;
10815f2f72a2SFrançois Revol 					}
10825f2f72a2SFrançois Revol 				}
10839c89c450SAxel Dörfler 
10849c89c450SAxel Dörfler 				if (dynamic_cast<ActivityMonitor*>(be_app) == NULL) {
10859c89c450SAxel Dörfler 					// allow background color change in the replicant only
10869c89c450SAxel Dörfler 					fLegendBackgroundColor = *color;
10871201d52eSAxel Dörfler 					SetLowColor(fLegendBackgroundColor);
10889c89c450SAxel Dörfler 					Invalidate(legendFrame);
10899c89c450SAxel Dörfler 				}
1090c28f8ea3SFrançois Revol 			}
1091c28f8ea3SFrançois Revol 			return;
1092c28f8ea3SFrançois Revol 		}
10939c89c450SAxel Dörfler 	}
10949c89c450SAxel Dörfler 
109518d3e65eSAxel Dörfler 	switch (message->what) {
109618d3e65eSAxel Dörfler 		case B_ABOUT_REQUESTED:
109718d3e65eSAxel Dörfler 			ActivityMonitor::ShowAbout();
109818d3e65eSAxel Dörfler 			break;
109918d3e65eSAxel Dörfler 
11001bb87bd0SAxel Dörfler 		case kMsgUpdateResolution:
11011bb87bd0SAxel Dörfler 		{
11021bb87bd0SAxel Dörfler 			int32 resolution;
11031bb87bd0SAxel Dörfler 			if (message->FindInt32("resolution", &resolution) != B_OK)
11041bb87bd0SAxel Dörfler 				break;
11051bb87bd0SAxel Dörfler 
11061bb87bd0SAxel Dörfler 			_UpdateResolution(resolution, false);
11071bb87bd0SAxel Dörfler 			break;
11081bb87bd0SAxel Dörfler 		}
11091bb87bd0SAxel Dörfler 
11101bb87bd0SAxel Dörfler 		case kMsgTimeIntervalUpdated:
11111bb87bd0SAxel Dörfler 			bigtime_t interval;
11121bb87bd0SAxel Dörfler 			if (message->FindInt64("interval", &interval) != B_OK)
11131bb87bd0SAxel Dörfler 				break;
11141bb87bd0SAxel Dörfler 
11151bb87bd0SAxel Dörfler 			if (interval < 10000)
11161bb87bd0SAxel Dörfler 				interval = 10000;
11171bb87bd0SAxel Dörfler 
11181bb87bd0SAxel Dörfler 			atomic_set64(&fRefreshInterval, interval);
11191bb87bd0SAxel Dörfler 			break;
11201bb87bd0SAxel Dörfler 
112118d3e65eSAxel Dörfler 		case kMsgToggleDataSource:
112218d3e65eSAxel Dörfler 		{
112318d3e65eSAxel Dörfler 			int32 index;
112418d3e65eSAxel Dörfler 			if (message->FindInt32("index", &index) != B_OK)
112518d3e65eSAxel Dörfler 				break;
112618d3e65eSAxel Dörfler 
112718d3e65eSAxel Dörfler 			const DataSource* baseSource = DataSource::SourceAt(index);
112818d3e65eSAxel Dörfler 			if (baseSource == NULL)
112918d3e65eSAxel Dörfler 				break;
113018d3e65eSAxel Dörfler 
11313a4a2141SAxel Dörfler 			DataSource* source = FindDataSource(baseSource);
113218d3e65eSAxel Dörfler 			if (source == NULL)
11333a4a2141SAxel Dörfler 				AddDataSource(baseSource);
113418d3e65eSAxel Dörfler 			else
11357d33b63dSAxel Dörfler 				RemoveDataSource(baseSource);
113618d3e65eSAxel Dörfler 
113718d3e65eSAxel Dörfler 			Invalidate();
113818d3e65eSAxel Dörfler 			break;
113918d3e65eSAxel Dörfler 		}
114018d3e65eSAxel Dörfler 
11413a4a2141SAxel Dörfler 		case kMsgToggleLegend:
11423a4a2141SAxel Dörfler 			fShowLegend = !fShowLegend;
11433a4a2141SAxel Dörfler 			Invalidate();
11443a4a2141SAxel Dörfler 			break;
11453a4a2141SAxel Dörfler 
114618d3e65eSAxel Dörfler 		case B_MOUSE_WHEEL_CHANGED:
114718d3e65eSAxel Dörfler 		{
114818d3e65eSAxel Dörfler 			float deltaY = 0.0f;
114918d3e65eSAxel Dörfler 			if (message->FindFloat("be:wheel_delta_y", &deltaY) != B_OK
115018d3e65eSAxel Dörfler 				|| deltaY == 0.0f)
115118d3e65eSAxel Dörfler 				break;
115218d3e65eSAxel Dörfler 
11531bb87bd0SAxel Dörfler 			int32 resolution = fDrawResolution;
115418d3e65eSAxel Dörfler 			if (deltaY > 0)
11551bb87bd0SAxel Dörfler 				resolution *= 2;
115618d3e65eSAxel Dörfler 			else
11571bb87bd0SAxel Dörfler 				resolution /= 2;
115818d3e65eSAxel Dörfler 
11591bb87bd0SAxel Dörfler 			_UpdateResolution(resolution);
116018d3e65eSAxel Dörfler 			break;
116118d3e65eSAxel Dörfler 		}
116218d3e65eSAxel Dörfler 
116318d3e65eSAxel Dörfler 		default:
116418d3e65eSAxel Dörfler 			BView::MessageReceived(message);
116518d3e65eSAxel Dörfler 			break;
116618d3e65eSAxel Dörfler 	}
116718d3e65eSAxel Dörfler }
116818d3e65eSAxel Dörfler 
116918d3e65eSAxel Dörfler 
1170065e8de0SAxel Dörfler void
1171065e8de0SAxel Dörfler ActivityView::_UpdateFrame()
1172065e8de0SAxel Dörfler {
1173dc1ffc79SFrançois Revol #ifdef __HAIKU__
1174065e8de0SAxel Dörfler 	if (fLegendLayoutItem == NULL || fHistoryLayoutItem == NULL)
1175065e8de0SAxel Dörfler 		return;
1176065e8de0SAxel Dörfler 
1177065e8de0SAxel Dörfler 	BRect historyFrame = fHistoryLayoutItem->Frame();
1178065e8de0SAxel Dörfler 	BRect legendFrame = fLegendLayoutItem->Frame();
1179dc1ffc79SFrançois Revol #else
1180dc1ffc79SFrançois Revol 	BRect historyFrame = Bounds();
1181dc1ffc79SFrançois Revol 	BRect legendFrame = Bounds();
1182dc1ffc79SFrançois Revol 	historyFrame.bottom -= 2 * Bounds().Height() / 3;
1183dc1ffc79SFrançois Revol 	legendFrame.top += Bounds().Height() / 3;
1184dc1ffc79SFrançois Revol #endif
1185065e8de0SAxel Dörfler 	MoveTo(historyFrame.left, historyFrame.top);
1186065e8de0SAxel Dörfler 	ResizeTo(legendFrame.left + legendFrame.Width() - historyFrame.left,
1187065e8de0SAxel Dörfler 		legendFrame.top + legendFrame.Height() - historyFrame.top);
1188065e8de0SAxel Dörfler }
1189065e8de0SAxel Dörfler 
1190065e8de0SAxel Dörfler 
11913a4a2141SAxel Dörfler BRect
11923a4a2141SAxel Dörfler ActivityView::_HistoryFrame() const
11933a4a2141SAxel Dörfler {
11943a4a2141SAxel Dörfler 	BRect frame = Bounds();
11953a4a2141SAxel Dörfler 
1196ed1b2753SStephan Aßmus 	if (fShowLegend) {
1197ed1b2753SStephan Aßmus 		BRect legendFrame = _LegendFrame();
11983a4a2141SAxel Dörfler 		frame.bottom = legendFrame.top - 1;
1199ed1b2753SStephan Aßmus 	}
1200ed1b2753SStephan Aßmus 
1201ed1b2753SStephan Aßmus 	frame.InsetBy(2, 2);
12023a4a2141SAxel Dörfler 
12033a4a2141SAxel Dörfler 	return frame;
12043a4a2141SAxel Dörfler }
12053a4a2141SAxel Dörfler 
12063a4a2141SAxel Dörfler 
1207065e8de0SAxel Dörfler float
1208065e8de0SAxel Dörfler ActivityView::_LegendHeight() const
12093a4a2141SAxel Dörfler {
12103a4a2141SAxel Dörfler 	font_height fontHeight;
12113a4a2141SAxel Dörfler 	GetFontHeight(&fontHeight);
12123a4a2141SAxel Dörfler 
1213d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
1214d4216445SAxel Dörfler 
12153a4a2141SAxel Dörfler 	int32 rows = (fSources.CountItems() + 1) / 2;
1216065e8de0SAxel Dörfler 	return rows * (4 + ceilf(fontHeight.ascent)
12173a4a2141SAxel Dörfler 		+ ceilf(fontHeight.descent) + ceilf(fontHeight.leading));
1218065e8de0SAxel Dörfler }
1219065e8de0SAxel Dörfler 
1220065e8de0SAxel Dörfler 
1221065e8de0SAxel Dörfler BRect
1222065e8de0SAxel Dörfler ActivityView::_LegendFrame() const
1223065e8de0SAxel Dörfler {
1224065e8de0SAxel Dörfler 	float height;
1225dc1ffc79SFrançois Revol #ifdef __HAIKU__
1226065e8de0SAxel Dörfler 	if (fLegendLayoutItem != NULL)
1227065e8de0SAxel Dörfler 		height = fLegendLayoutItem->Frame().Height();
1228065e8de0SAxel Dörfler 	else
1229dc1ffc79SFrançois Revol #endif
1230065e8de0SAxel Dörfler 		height = _LegendHeight();
1231065e8de0SAxel Dörfler 
1232065e8de0SAxel Dörfler 	BRect frame = Bounds();
1233065e8de0SAxel Dörfler 	frame.top = frame.bottom - height;
12343a4a2141SAxel Dörfler 
12353a4a2141SAxel Dörfler 	return frame;
12363a4a2141SAxel Dörfler }
12373a4a2141SAxel Dörfler 
12383a4a2141SAxel Dörfler 
12393a4a2141SAxel Dörfler BRect
12403a4a2141SAxel Dörfler ActivityView::_LegendFrameAt(BRect frame, int32 index) const
12413a4a2141SAxel Dörfler {
12423a4a2141SAxel Dörfler 	int32 column = index & 1;
12433a4a2141SAxel Dörfler 	int32 row = index / 2;
12443a4a2141SAxel Dörfler 	if (column == 0)
12453a4a2141SAxel Dörfler 		frame.right = frame.left + floorf(frame.Width() / 2) - 5;
12463a4a2141SAxel Dörfler 	else
12473a4a2141SAxel Dörfler 		frame.left = frame.right - floorf(frame.Width() / 2) + 5;
12483a4a2141SAxel Dörfler 
1249d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
1250d4216445SAxel Dörfler 
12513a4a2141SAxel Dörfler 	int32 rows = (fSources.CountItems() + 1) / 2;
12523a4a2141SAxel Dörfler 	float height = floorf((frame.Height() - 5) / rows);
12533a4a2141SAxel Dörfler 
12543a4a2141SAxel Dörfler 	frame.top = frame.top + 5 + row * height;
12553a4a2141SAxel Dörfler 	frame.bottom = frame.top + height - 1;
12563a4a2141SAxel Dörfler 
12573a4a2141SAxel Dörfler 	return frame;
12583a4a2141SAxel Dörfler }
12593a4a2141SAxel Dörfler 
12603a4a2141SAxel Dörfler 
12611201d52eSAxel Dörfler BRect
12621201d52eSAxel Dörfler ActivityView::_LegendColorFrameAt(BRect frame, int32 index) const
12631201d52eSAxel Dörfler {
12641201d52eSAxel Dörfler 	frame = _LegendFrameAt(frame, index);
12651201d52eSAxel Dörfler 	frame.InsetBy(1, 1);
12661201d52eSAxel Dörfler 	frame.right = frame.left + frame.Height();
12671201d52eSAxel Dörfler 
12681201d52eSAxel Dörfler 	return frame;
12691201d52eSAxel Dörfler }
12701201d52eSAxel Dörfler 
12711201d52eSAxel Dörfler 
127218d3e65eSAxel Dörfler float
127318d3e65eSAxel Dörfler ActivityView::_PositionForValue(DataSource* source, DataHistory* values,
127418d3e65eSAxel Dörfler 	int64 value)
127518d3e65eSAxel Dörfler {
127618d3e65eSAxel Dörfler 	int64 min = source->Minimum();
127718d3e65eSAxel Dörfler 	int64 max = source->Maximum();
127818d3e65eSAxel Dörfler 	if (source->AdaptiveScale()) {
127918d3e65eSAxel Dörfler 		int64 adaptiveMax = int64(values->MaximumValue() * 1.2);
128018d3e65eSAxel Dörfler 		if (adaptiveMax < max)
128118d3e65eSAxel Dörfler 			max = adaptiveMax;
128218d3e65eSAxel Dörfler 	}
128318d3e65eSAxel Dörfler 
128418d3e65eSAxel Dörfler 	if (value > max)
128518d3e65eSAxel Dörfler 		value = max;
128618d3e65eSAxel Dörfler 	if (value < min)
128718d3e65eSAxel Dörfler 		value = min;
128818d3e65eSAxel Dörfler 
12893a4a2141SAxel Dörfler 	float height = _HistoryFrame().Height();
129018d3e65eSAxel Dörfler 	return height - (value - min) * height / (max - min);
129118d3e65eSAxel Dörfler }
129218d3e65eSAxel Dörfler 
129318d3e65eSAxel Dörfler 
129418d3e65eSAxel Dörfler void
1295ed1b2753SStephan Aßmus ActivityView::_DrawHistory(bool drawBackground)
129618d3e65eSAxel Dörfler {
12973a4a2141SAxel Dörfler 	_UpdateOffscreenBitmap();
12983a4a2141SAxel Dörfler 
12993a4a2141SAxel Dörfler 	BView* view = this;
13003a4a2141SAxel Dörfler 	if (fOffscreen != NULL) {
13013a4a2141SAxel Dörfler 		fOffscreen->Lock();
13029c89c450SAxel Dörfler 		view = _OffscreenView();
13033a4a2141SAxel Dörfler 	}
13043a4a2141SAxel Dörfler 
13053a4a2141SAxel Dörfler 	BRect frame = _HistoryFrame();
1306ed1b2753SStephan Aßmus 	BRect outerFrame = frame.InsetByCopy(-2, -2);
1307ed1b2753SStephan Aßmus 
1308ed1b2753SStephan Aßmus 	// draw the outer frame
1309ed1b2753SStephan Aßmus 	uint32 flags = 0;
1310ed1b2753SStephan Aßmus 	if (!drawBackground)
1311ed1b2753SStephan Aßmus 		flags |= BControlLook::B_BLEND_FRAME;
1312ed1b2753SStephan Aßmus 	be_control_look->DrawTextControlBorder(this, outerFrame,
1313ed1b2753SStephan Aßmus 		outerFrame, fLegendBackgroundColor, flags);
1314ed1b2753SStephan Aßmus 
1315ed1b2753SStephan Aßmus 	// convert to offscreen view if necessary
1316ed1b2753SStephan Aßmus 	if (view != this)
1317ed1b2753SStephan Aßmus 		frame.OffsetTo(B_ORIGIN);
1318ed1b2753SStephan Aßmus 
13191201d52eSAxel Dörfler 	view->SetLowColor(fHistoryBackgroundColor);
13203a4a2141SAxel Dörfler 	view->FillRect(frame, B_SOLID_LOW);
13213a4a2141SAxel Dörfler 
132218d3e65eSAxel Dörfler 	uint32 step = 2;
132318d3e65eSAxel Dörfler 	uint32 resolution = fDrawResolution;
132418d3e65eSAxel Dörfler 	if (fDrawResolution > 1) {
132518d3e65eSAxel Dörfler 		step = 1;
132618d3e65eSAxel Dörfler 		resolution--;
132718d3e65eSAxel Dörfler 	}
132818d3e65eSAxel Dörfler 
13293a4a2141SAxel Dörfler 	uint32 width = frame.IntegerWidth() - 10;
133018d3e65eSAxel Dörfler 	uint32 steps = width / step;
13311bb87bd0SAxel Dörfler 	bigtime_t timeStep = RefreshInterval() * resolution;
133218d3e65eSAxel Dörfler 	bigtime_t now = system_time();
133318d3e65eSAxel Dörfler 
13341201d52eSAxel Dörfler 	// Draw scale
13351201d52eSAxel Dörfler 	// TODO: add second markers?
13361201d52eSAxel Dörfler 
13373a4a2141SAxel Dörfler 	view->SetPenSize(1);
13383a4a2141SAxel Dörfler 
13391201d52eSAxel Dörfler 	rgb_color scaleColor = view->LowColor();
13401201d52eSAxel Dörfler 	uint32 average = (scaleColor.red + scaleColor.green + scaleColor.blue) / 3;
13411201d52eSAxel Dörfler 	if (average < 96)
13421201d52eSAxel Dörfler 		scaleColor = tint_color(scaleColor, B_LIGHTEN_2_TINT);
13431201d52eSAxel Dörfler 	else
13441201d52eSAxel Dörfler 		scaleColor = tint_color(scaleColor, B_DARKEN_2_TINT);
13451201d52eSAxel Dörfler 
13461201d52eSAxel Dörfler 	view->SetHighColor(scaleColor);
13473a4a2141SAxel Dörfler 	view->StrokeLine(BPoint(frame.left, frame.top + frame.Height() / 2),
13483a4a2141SAxel Dörfler 		BPoint(frame.right, frame.top + frame.Height() / 2));
13493a4a2141SAxel Dörfler 
13501201d52eSAxel Dörfler 	// Draw values
13511201d52eSAxel Dörfler 
13521bb87bd0SAxel Dörfler 	view->SetPenSize(1.5);
1353d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
135418d3e65eSAxel Dörfler 
135518d3e65eSAxel Dörfler 	for (uint32 i = fSources.CountItems(); i-- > 0;) {
13568e26f387SAxel Dörfler 		ViewHistory* viewValues = fViewValues.ItemAt(i);
135718d3e65eSAxel Dörfler 		DataSource* source = fSources.ItemAt(i);
135818d3e65eSAxel Dörfler 		DataHistory* values = fValues.ItemAt(i);
135918d3e65eSAxel Dörfler 
13608e26f387SAxel Dörfler 		viewValues->Update(values, steps, fDrawResolution, now, timeStep,
13618e26f387SAxel Dörfler 			RefreshInterval());
13628e26f387SAxel Dörfler 
13638e26f387SAxel Dörfler 		uint32 x = viewValues->Start() * step;
13648e26f387SAxel Dörfler 		BShape shape;
13658e26f387SAxel Dörfler 		bool first = true;
13668e26f387SAxel Dörfler 
13678e26f387SAxel Dörfler 		for (uint32 i = viewValues->Start(); i < steps; x += step, i++) {
13688e26f387SAxel Dörfler 			float y = _PositionForValue(source, values,
13698e26f387SAxel Dörfler 				viewValues->ValueAt(i));
13708e26f387SAxel Dörfler 
13718e26f387SAxel Dörfler 			if (first) {
13728e26f387SAxel Dörfler 				shape.MoveTo(BPoint(x, y));
13738e26f387SAxel Dörfler 				first = false;
13748e26f387SAxel Dörfler 			} else
13758e26f387SAxel Dörfler 				shape.LineTo(BPoint(x, y));
13768e26f387SAxel Dörfler 		}
13778e26f387SAxel Dörfler 
13783a4a2141SAxel Dörfler 		view->SetHighColor(source->Color());
13798e26f387SAxel Dörfler 		view->SetLineMode(B_BUTT_CAP, B_ROUND_JOIN);
13808e26f387SAxel Dörfler 		view->MovePenTo(B_ORIGIN);
13818e26f387SAxel Dörfler 		view->StrokeShape(&shape);
138218d3e65eSAxel Dörfler 	}
138318d3e65eSAxel Dörfler 
138418d3e65eSAxel Dörfler 	// TODO: add marks when an app started or quit
13853a4a2141SAxel Dörfler 	view->Sync();
13863a4a2141SAxel Dörfler 	if (fOffscreen != NULL) {
13873a4a2141SAxel Dörfler 		fOffscreen->Unlock();
1388ed1b2753SStephan Aßmus 		DrawBitmap(fOffscreen, outerFrame.LeftTop());
13893a4a2141SAxel Dörfler 	}
13903a4a2141SAxel Dörfler }
13913a4a2141SAxel Dörfler 
13923a4a2141SAxel Dörfler 
13933a4a2141SAxel Dörfler void
13941bb87bd0SAxel Dörfler ActivityView::_UpdateResolution(int32 resolution, bool broadcast)
13951bb87bd0SAxel Dörfler {
13961bb87bd0SAxel Dörfler 	if (resolution < 1)
13971bb87bd0SAxel Dörfler 		resolution = 1;
13981bb87bd0SAxel Dörfler 	if (resolution > 128)
13991bb87bd0SAxel Dörfler 		resolution = 128;
14001bb87bd0SAxel Dörfler 
14011bb87bd0SAxel Dörfler 	if (resolution == fDrawResolution)
14021bb87bd0SAxel Dörfler 		return;
14031bb87bd0SAxel Dörfler 
14041bb87bd0SAxel Dörfler 	ActivityWindow* window = dynamic_cast<ActivityWindow*>(Window());
14051bb87bd0SAxel Dörfler 	if (broadcast && window != NULL) {
14061bb87bd0SAxel Dörfler 		BMessage update(kMsgUpdateResolution);
14071bb87bd0SAxel Dörfler 		update.AddInt32("resolution", resolution);
14081bb87bd0SAxel Dörfler 		window->BroadcastToActivityViews(&update, this);
14091bb87bd0SAxel Dörfler 	}
14101bb87bd0SAxel Dörfler 
14111bb87bd0SAxel Dörfler 	fDrawResolution = resolution;
14121bb87bd0SAxel Dörfler 	Invalidate();
14131bb87bd0SAxel Dörfler }
14141bb87bd0SAxel Dörfler 
14151bb87bd0SAxel Dörfler 
14161bb87bd0SAxel Dörfler void
1417ed1b2753SStephan Aßmus ActivityView::Draw(BRect updateRect)
14183a4a2141SAxel Dörfler {
1419ed1b2753SStephan Aßmus 	bool drawBackground = true;
1420ed1b2753SStephan Aßmus 	if (Parent() && (Parent()->Flags() & B_DRAW_ON_CHILDREN) != 0)
1421ed1b2753SStephan Aßmus 		drawBackground = false;
1422ed1b2753SStephan Aßmus 
1423ed1b2753SStephan Aßmus 	_DrawHistory(drawBackground);
14243a4a2141SAxel Dörfler 
14253a4a2141SAxel Dörfler 	if (!fShowLegend)
14263a4a2141SAxel Dörfler 		return;
14273a4a2141SAxel Dörfler 
14283a4a2141SAxel Dörfler 	// draw legend
1429ed1b2753SStephan Aßmus 	BRect legendFrame = _LegendFrame();
1430ed1b2753SStephan Aßmus 	SetLowColor(fLegendBackgroundColor);
1431ed1b2753SStephan Aßmus 	if (drawBackground)
1432ed1b2753SStephan Aßmus 		FillRect(legendFrame, B_SOLID_LOW);
14333a4a2141SAxel Dörfler 
1434d4216445SAxel Dörfler 	BAutolock _(fSourcesLock);
14353a4a2141SAxel Dörfler 
14363a4a2141SAxel Dörfler 	font_height fontHeight;
14373a4a2141SAxel Dörfler 	GetFontHeight(&fontHeight);
14383a4a2141SAxel Dörfler 
14393a4a2141SAxel Dörfler 	for (int32 i = 0; i < fSources.CountItems(); i++) {
14403a4a2141SAxel Dörfler 		DataSource* source = fSources.ItemAt(i);
14413a4a2141SAxel Dörfler 		DataHistory* values = fValues.ItemAt(i);
14423a4a2141SAxel Dörfler 		BRect frame = _LegendFrameAt(legendFrame, i);
14433a4a2141SAxel Dörfler 
14443a4a2141SAxel Dörfler 		// draw color box
14451201d52eSAxel Dörfler 		BRect colorBox = _LegendColorFrameAt(legendFrame, i);
1446ed1b2753SStephan Aßmus 		BRect rect = colorBox;
1447ed1b2753SStephan Aßmus 		uint32 flags = BControlLook::B_BLEND_FRAME;
1448ed1b2753SStephan Aßmus 		be_control_look->DrawTextControlBorder(this, rect,
1449ed1b2753SStephan Aßmus 			rect, fLegendBackgroundColor, flags);
14503a4a2141SAxel Dörfler 		SetHighColor(source->Color());
1451ed1b2753SStephan Aßmus 		FillRect(rect);
14523a4a2141SAxel Dörfler 
14533a4a2141SAxel Dörfler 		// show current value and label
14543a4a2141SAxel Dörfler 		float y = frame.top + ceilf(fontHeight.ascent);
14553a4a2141SAxel Dörfler 		int64 value = values->ValueAt(values->End());
14563a4a2141SAxel Dörfler 		BString text;
14573a4a2141SAxel Dörfler 		source->Print(text, value);
14583a4a2141SAxel Dörfler 		float width = StringWidth(text.String());
14593a4a2141SAxel Dörfler 
14603a4a2141SAxel Dörfler 		BString label = source->Label();
1461ed1b2753SStephan Aßmus 		float possibleLabelWidth = frame.right - colorBox.right - 12 - width;
1462ed1b2753SStephan Aßmus 		// TODO: TruncateString() is broken... remove + 5 when fixed!
1463ed1b2753SStephan Aßmus 		if (ceilf(StringWidth(label.String()) + 5) > possibleLabelWidth)
1464ed1b2753SStephan Aßmus 			label = source->ShortLabel();
1465ed1b2753SStephan Aßmus 		TruncateString(&label, B_TRUNCATE_MIDDLE, possibleLabelWidth);
14663a4a2141SAxel Dörfler 
1467ed1b2753SStephan Aßmus 		if (drawBackground)
14683a4a2141SAxel Dörfler 			SetHighColor(ui_color(B_CONTROL_TEXT_COLOR));
1469ed1b2753SStephan Aßmus 		else {
1470ed1b2753SStephan Aßmus 			SetDrawingMode(B_OP_OVER);
1471ed1b2753SStephan Aßmus 			rgb_color c = Parent()->LowColor();
1472ed1b2753SStephan Aßmus 			if (c.red + c.green + c.blue > 128 * 3)
1473ed1b2753SStephan Aßmus 				SetHighColor(0, 0, 0);
1474ed1b2753SStephan Aßmus 			else
1475ed1b2753SStephan Aßmus 				SetHighColor(255, 255, 255);
1476ed1b2753SStephan Aßmus 		}
14773a4a2141SAxel Dörfler 		DrawString(label.String(), BPoint(6 + colorBox.right, y));
14783a4a2141SAxel Dörfler 		DrawString(text.String(), BPoint(frame.right - width, y));
14793a4a2141SAxel Dörfler 	}
148018d3e65eSAxel Dörfler }
148118d3e65eSAxel Dörfler 
148218d3e65eSAxel Dörfler 
148318d3e65eSAxel Dörfler void
148418d3e65eSAxel Dörfler ActivityView::_Refresh()
148518d3e65eSAxel Dörfler {
14861bb87bd0SAxel Dörfler 	bigtime_t lastTimeout = system_time() - RefreshInterval();
14874ce1e1d2SAxel Dörfler 	BMessenger target(this);
148818d3e65eSAxel Dörfler 
1489d4216445SAxel Dörfler 	while (true) {
1490d4216445SAxel Dörfler 		status_t status = acquire_sem_etc(fRefreshSem, 1, B_ABSOLUTE_TIMEOUT,
14911bb87bd0SAxel Dörfler 			lastTimeout + RefreshInterval());
1492d4216445SAxel Dörfler 		if (status == B_OK || status == B_BAD_SEM_ID)
1493d4216445SAxel Dörfler 			break;
1494d4216445SAxel Dörfler 		if (status == B_INTERRUPTED)
1495d4216445SAxel Dörfler 			continue;
1496d4216445SAxel Dörfler 
1497d4216445SAxel Dörfler 		SystemInfo info(fSystemInfoHandler);
14981bb87bd0SAxel Dörfler 		lastTimeout += RefreshInterval();
1499d4216445SAxel Dörfler 
1500d4216445SAxel Dörfler 		fSourcesLock.Lock();
150118d3e65eSAxel Dörfler 
150218d3e65eSAxel Dörfler 		for (uint32 i = fSources.CountItems(); i-- > 0;) {
150318d3e65eSAxel Dörfler 			DataSource* source = fSources.ItemAt(i);
150418d3e65eSAxel Dörfler 			DataHistory* values = fValues.ItemAt(i);
150518d3e65eSAxel Dörfler 
150618d3e65eSAxel Dörfler 			int64 value = source->NextValue(info);
150718d3e65eSAxel Dörfler 			values->AddValue(info.Time(), value);
150818d3e65eSAxel Dörfler 		}
150918d3e65eSAxel Dörfler 
1510d4216445SAxel Dörfler 		fSourcesLock.Unlock();
1511d4216445SAxel Dörfler 
15124ce1e1d2SAxel Dörfler 		target.SendMessage(B_INVALIDATE);
151318d3e65eSAxel Dörfler 	}
1514d4216445SAxel Dörfler }
151518d3e65eSAxel Dörfler 
1516d4216445SAxel Dörfler 
1517d4216445SAxel Dörfler /*static*/ status_t
1518d4216445SAxel Dörfler ActivityView::_RefreshThread(void* self)
1519d4216445SAxel Dörfler {
1520d4216445SAxel Dörfler 	((ActivityView*)self)->_Refresh();
1521d4216445SAxel Dörfler 	return B_OK;
1522d4216445SAxel Dörfler }
1523