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> 12*8e26f387SAxel Dörfler #include <vector.h> 1318d3e65eSAxel Dörfler 14dc1ffc79SFrançois Revol #ifdef __HAIKU__ 15065e8de0SAxel Dörfler # include <AbstractLayoutItem.h> 16dc1ffc79SFrançois Revol #endif 1718d3e65eSAxel Dörfler #include <Application.h> 18d4216445SAxel Dörfler #include <Autolock.h> 1918d3e65eSAxel Dörfler #include <Bitmap.h> 2018d3e65eSAxel Dörfler #include <Dragger.h> 2118d3e65eSAxel Dörfler #include <MenuItem.h> 2218d3e65eSAxel Dörfler #include <MessageRunner.h> 2318d3e65eSAxel Dörfler #include <PopUpMenu.h> 24*8e26f387SAxel Dörfler #include <Shape.h> 2518d3e65eSAxel Dörfler #include <String.h> 2618d3e65eSAxel Dörfler 2718d3e65eSAxel Dörfler #include "ActivityMonitor.h" 283f315b26SAxel Dörfler #include "ActivityWindow.h" 291bb87bd0SAxel Dörfler #include "SettingsWindow.h" 3018d3e65eSAxel Dörfler #include "SystemInfo.h" 3174158bb4SFrançois Revol #include "SystemInfoHandler.h" 3218d3e65eSAxel Dörfler 3318d3e65eSAxel Dörfler 34*8e26f387SAxel Dörfler template<typename ObjectType> 35*8e26f387SAxel Dörfler class ListAddDeleter { 36*8e26f387SAxel Dörfler public: 37*8e26f387SAxel Dörfler ListAddDeleter(BObjectList<ObjectType>& list, ObjectType* object, 38*8e26f387SAxel Dörfler int32 spot) 39*8e26f387SAxel Dörfler : 40*8e26f387SAxel Dörfler fList(list), 41*8e26f387SAxel Dörfler fObject(object) 42*8e26f387SAxel Dörfler { 43*8e26f387SAxel Dörfler if (fObject != NULL && !fList.AddItem(fObject, spot)) { 44*8e26f387SAxel Dörfler delete fObject; 45*8e26f387SAxel Dörfler fObject = NULL; 46*8e26f387SAxel Dörfler } 47*8e26f387SAxel Dörfler } 48*8e26f387SAxel Dörfler 49*8e26f387SAxel Dörfler ~ListAddDeleter() 50*8e26f387SAxel Dörfler { 51*8e26f387SAxel Dörfler if (fObject != NULL) { 52*8e26f387SAxel Dörfler fList.RemoveItem(fObject); 53*8e26f387SAxel Dörfler delete fObject; 54*8e26f387SAxel Dörfler } 55*8e26f387SAxel Dörfler } 56*8e26f387SAxel Dörfler 57*8e26f387SAxel Dörfler bool Failed() const 58*8e26f387SAxel Dörfler { 59*8e26f387SAxel Dörfler return fObject == NULL; 60*8e26f387SAxel Dörfler } 61*8e26f387SAxel Dörfler 62*8e26f387SAxel Dörfler void Detach() 63*8e26f387SAxel Dörfler { 64*8e26f387SAxel Dörfler fObject = NULL; 65*8e26f387SAxel Dörfler } 66*8e26f387SAxel Dörfler 67*8e26f387SAxel Dörfler private: 68*8e26f387SAxel Dörfler BObjectList<ObjectType>& fList; 69*8e26f387SAxel Dörfler ObjectType* fObject; 70*8e26f387SAxel Dörfler }; 71*8e26f387SAxel Dörfler 72*8e26f387SAxel Dörfler 73*8e26f387SAxel Dörfler /*! This class manages the scale of a history with a dynamic scale. 74*8e26f387SAxel Dörfler Every history value will be input via Update(), and the minimum/maximum 75*8e26f387SAxel Dörfler is computed from that. 76*8e26f387SAxel Dörfler */ 7751591198SAxel Dörfler class Scale { 7851591198SAxel Dörfler public: 7951591198SAxel Dörfler Scale(scale_type type); 8051591198SAxel Dörfler 8151591198SAxel Dörfler int64 MinimumValue() const { return fMinimumValue; } 8251591198SAxel Dörfler int64 MaximumValue() const { return fMaximumValue; } 8351591198SAxel Dörfler 8451591198SAxel Dörfler void Update(int64 value); 8551591198SAxel Dörfler 8651591198SAxel Dörfler private: 8751591198SAxel Dörfler scale_type fType; 8851591198SAxel Dörfler int64 fMinimumValue; 8951591198SAxel Dörfler int64 fMaximumValue; 9051591198SAxel Dörfler bool fInitialized; 9151591198SAxel Dörfler }; 9251591198SAxel Dörfler 93*8e26f387SAxel Dörfler /*! Stores the interpolated on screen view values. This is done so that the 94*8e26f387SAxel Dörfler interpolation is fixed, and does not change when being scrolled. 95*8e26f387SAxel Dörfler 96*8e26f387SAxel Dörfler We could also just do this by making sure we always ask for the same 97*8e26f387SAxel Dörfler interval only, but this way we also save the interpolation. 98*8e26f387SAxel Dörfler */ 99*8e26f387SAxel Dörfler class ViewHistory { 100*8e26f387SAxel Dörfler public: 101*8e26f387SAxel Dörfler ViewHistory(); 102*8e26f387SAxel Dörfler 103*8e26f387SAxel Dörfler int64 ValueAt(int32 x); 104*8e26f387SAxel Dörfler 105*8e26f387SAxel Dörfler int32 Start() const 106*8e26f387SAxel Dörfler { return fValues.Size() 107*8e26f387SAxel Dörfler - fValues.CountItems(); } 108*8e26f387SAxel Dörfler 109*8e26f387SAxel Dörfler void Update(DataHistory* history, int32 width, 110*8e26f387SAxel Dörfler int32 resolution, bigtime_t toTime, 111*8e26f387SAxel Dörfler bigtime_t step, bigtime_t refresh); 112*8e26f387SAxel Dörfler 113*8e26f387SAxel Dörfler private: 114*8e26f387SAxel Dörfler CircularBuffer<int64> fValues; 115*8e26f387SAxel Dörfler int32 fResolution; 116*8e26f387SAxel Dörfler bigtime_t fRefresh; 117*8e26f387SAxel Dörfler bigtime_t fLastTime; 118*8e26f387SAxel Dörfler }; 119*8e26f387SAxel Dörfler 12018d3e65eSAxel Dörfler struct data_item { 12118d3e65eSAxel Dörfler bigtime_t time; 12218d3e65eSAxel Dörfler int64 value; 12318d3e65eSAxel Dörfler }; 12418d3e65eSAxel Dörfler 125dc1ffc79SFrançois Revol #ifdef __HAIKU__ 126065e8de0SAxel Dörfler class ActivityView::HistoryLayoutItem : public BAbstractLayoutItem { 127065e8de0SAxel Dörfler public: 128065e8de0SAxel Dörfler HistoryLayoutItem(ActivityView* parent); 129065e8de0SAxel Dörfler 130065e8de0SAxel Dörfler virtual bool IsVisible(); 131065e8de0SAxel Dörfler virtual void SetVisible(bool visible); 132065e8de0SAxel Dörfler 133065e8de0SAxel Dörfler virtual BRect Frame(); 134065e8de0SAxel Dörfler virtual void SetFrame(BRect frame); 135065e8de0SAxel Dörfler 136065e8de0SAxel Dörfler virtual BView* View(); 137065e8de0SAxel Dörfler 138065e8de0SAxel Dörfler virtual BSize BasePreferredSize(); 139065e8de0SAxel Dörfler 140065e8de0SAxel Dörfler private: 141065e8de0SAxel Dörfler ActivityView* fParent; 142065e8de0SAxel Dörfler BRect fFrame; 143065e8de0SAxel Dörfler }; 144065e8de0SAxel Dörfler 145065e8de0SAxel Dörfler class ActivityView::LegendLayoutItem : public BAbstractLayoutItem { 146065e8de0SAxel Dörfler public: 147065e8de0SAxel Dörfler LegendLayoutItem(ActivityView* parent); 148065e8de0SAxel Dörfler 149065e8de0SAxel Dörfler virtual bool IsVisible(); 150065e8de0SAxel Dörfler virtual void SetVisible(bool visible); 151065e8de0SAxel Dörfler 152065e8de0SAxel Dörfler virtual BRect Frame(); 153065e8de0SAxel Dörfler virtual void SetFrame(BRect frame); 154065e8de0SAxel Dörfler 155065e8de0SAxel Dörfler virtual BView* View(); 156065e8de0SAxel Dörfler 157065e8de0SAxel Dörfler virtual BSize BaseMinSize(); 158065e8de0SAxel Dörfler virtual BSize BaseMaxSize(); 159065e8de0SAxel Dörfler virtual BSize BasePreferredSize(); 160065e8de0SAxel Dörfler virtual BAlignment BaseAlignment(); 161065e8de0SAxel Dörfler 162065e8de0SAxel Dörfler private: 163065e8de0SAxel Dörfler ActivityView* fParent; 164065e8de0SAxel Dörfler BRect fFrame; 165065e8de0SAxel Dörfler }; 166dc1ffc79SFrançois Revol #endif 167065e8de0SAxel Dörfler 1681bb87bd0SAxel Dörfler const bigtime_t kInitialRefreshInterval = 250000LL; 16918d3e65eSAxel Dörfler 17018d3e65eSAxel Dörfler const uint32 kMsgToggleDataSource = 'tgds'; 1713a4a2141SAxel Dörfler const uint32 kMsgToggleLegend = 'tglg'; 1721bb87bd0SAxel Dörfler const uint32 kMsgUpdateResolution = 'ures'; 17318d3e65eSAxel Dörfler 17418d3e65eSAxel Dörfler extern const char* kSignature; 17518d3e65eSAxel Dörfler 17618d3e65eSAxel Dörfler 17751591198SAxel Dörfler Scale::Scale(scale_type type) 17851591198SAxel Dörfler : 17951591198SAxel Dörfler fType(type), 18051591198SAxel Dörfler fMinimumValue(0), 18151591198SAxel Dörfler fMaximumValue(0), 18251591198SAxel Dörfler fInitialized(false) 18351591198SAxel Dörfler { 18451591198SAxel Dörfler } 18551591198SAxel Dörfler 18651591198SAxel Dörfler 18751591198SAxel Dörfler void 18851591198SAxel Dörfler Scale::Update(int64 value) 18951591198SAxel Dörfler { 19051591198SAxel Dörfler if (!fInitialized || fMinimumValue > value) 19151591198SAxel Dörfler fMinimumValue = value; 192230e3259SAxel Dörfler if (!fInitialized || fMaximumValue < value) 19351591198SAxel Dörfler fMaximumValue = value; 19451591198SAxel Dörfler 19551591198SAxel Dörfler fInitialized = true; 19651591198SAxel Dörfler } 19751591198SAxel Dörfler 19851591198SAxel Dörfler 19951591198SAxel Dörfler // #pragma mark - 20051591198SAxel Dörfler 20151591198SAxel Dörfler 202*8e26f387SAxel Dörfler ViewHistory::ViewHistory() 203*8e26f387SAxel Dörfler : 204*8e26f387SAxel Dörfler fValues(1), 205*8e26f387SAxel Dörfler fResolution(-1), 206*8e26f387SAxel Dörfler fRefresh(-1), 207*8e26f387SAxel Dörfler fLastTime(0) 208*8e26f387SAxel Dörfler { 209*8e26f387SAxel Dörfler } 210*8e26f387SAxel Dörfler 211*8e26f387SAxel Dörfler 212*8e26f387SAxel Dörfler int64 213*8e26f387SAxel Dörfler ViewHistory::ValueAt(int32 x) 214*8e26f387SAxel Dörfler { 215*8e26f387SAxel Dörfler int64* value = fValues.ItemAt(x - Start()); 216*8e26f387SAxel Dörfler if (value != NULL) 217*8e26f387SAxel Dörfler return *value; 218*8e26f387SAxel Dörfler 219*8e26f387SAxel Dörfler return 0; 220*8e26f387SAxel Dörfler } 221*8e26f387SAxel Dörfler 222*8e26f387SAxel Dörfler 223*8e26f387SAxel Dörfler void 224*8e26f387SAxel Dörfler ViewHistory::Update(DataHistory* history, int32 width, int32 resolution, 225*8e26f387SAxel Dörfler bigtime_t toTime, bigtime_t step, bigtime_t refresh) 226*8e26f387SAxel Dörfler { 227*8e26f387SAxel Dörfler // Check if we need to invalidate the existing values 228*8e26f387SAxel Dörfler if ((int32)fValues.Size() != width 229*8e26f387SAxel Dörfler || fResolution != resolution 230*8e26f387SAxel Dörfler || fRefresh != refresh) { 231*8e26f387SAxel Dörfler fValues.SetSize(width); 232*8e26f387SAxel Dörfler fLastTime = 0; 233*8e26f387SAxel Dörfler fResolution = resolution; 234*8e26f387SAxel Dörfler fRefresh = refresh; 235*8e26f387SAxel Dörfler } 236*8e26f387SAxel Dörfler 237*8e26f387SAxel Dörfler // Compute how many new values we need to retrieve 238*8e26f387SAxel Dörfler if (fLastTime < history->Start()) 239*8e26f387SAxel Dörfler fLastTime = history->Start(); 240*8e26f387SAxel Dörfler 241*8e26f387SAxel Dörfler int32 updateWidth = int32((toTime - fLastTime) / step); 242*8e26f387SAxel Dörfler if (updateWidth < 1) 243*8e26f387SAxel Dörfler return; 244*8e26f387SAxel Dörfler 245*8e26f387SAxel Dörfler if (updateWidth > (int32)fValues.Size()) { 246*8e26f387SAxel Dörfler updateWidth = fValues.Size(); 247*8e26f387SAxel Dörfler fLastTime = toTime - updateWidth * step; 248*8e26f387SAxel Dörfler } 249*8e26f387SAxel Dörfler 250*8e26f387SAxel Dörfler for (int32 i = 0; i < updateWidth; i++) { 251*8e26f387SAxel Dörfler int64 value = history->ValueAt(fLastTime += step); 252*8e26f387SAxel Dörfler 253*8e26f387SAxel Dörfler if (step > refresh) { 254*8e26f387SAxel Dörfler uint32 count = 1; 255*8e26f387SAxel Dörfler for (bigtime_t offset = refresh; offset < step; offset += refresh) { 256*8e26f387SAxel Dörfler // TODO: handle int64 overflow correctly! 257*8e26f387SAxel Dörfler value += history->ValueAt(fLastTime + offset); 258*8e26f387SAxel Dörfler count++; 259*8e26f387SAxel Dörfler } 260*8e26f387SAxel Dörfler value /= count; 261*8e26f387SAxel Dörfler } 262*8e26f387SAxel Dörfler 263*8e26f387SAxel Dörfler fValues.AddItem(value); 264*8e26f387SAxel Dörfler } 265*8e26f387SAxel Dörfler } 266*8e26f387SAxel Dörfler 267*8e26f387SAxel Dörfler 268*8e26f387SAxel Dörfler // #pragma mark - 269*8e26f387SAxel Dörfler 270*8e26f387SAxel Dörfler 27118d3e65eSAxel Dörfler DataHistory::DataHistory(bigtime_t memorize, bigtime_t interval) 27218d3e65eSAxel Dörfler : 27318d3e65eSAxel Dörfler fBuffer(10000), 27418d3e65eSAxel Dörfler fMinimumValue(0), 27518d3e65eSAxel Dörfler fMaximumValue(0), 27618d3e65eSAxel Dörfler fRefreshInterval(interval), 27751591198SAxel Dörfler fLastIndex(-1), 27851591198SAxel Dörfler fScale(NULL) 27918d3e65eSAxel Dörfler { 28018d3e65eSAxel Dörfler } 28118d3e65eSAxel Dörfler 28218d3e65eSAxel Dörfler 28318d3e65eSAxel Dörfler DataHistory::~DataHistory() 28418d3e65eSAxel Dörfler { 28518d3e65eSAxel Dörfler } 28618d3e65eSAxel Dörfler 28718d3e65eSAxel Dörfler 28818d3e65eSAxel Dörfler void 28918d3e65eSAxel Dörfler DataHistory::AddValue(bigtime_t time, int64 value) 29018d3e65eSAxel Dörfler { 29118d3e65eSAxel Dörfler if (fBuffer.IsEmpty() || fMaximumValue < value) 29218d3e65eSAxel Dörfler fMaximumValue = value; 29318d3e65eSAxel Dörfler if (fBuffer.IsEmpty() || fMinimumValue > value) 29418d3e65eSAxel Dörfler fMinimumValue = value; 29551591198SAxel Dörfler if (fScale != NULL) 29651591198SAxel Dörfler fScale->Update(value); 29718d3e65eSAxel Dörfler 29818d3e65eSAxel Dörfler data_item item = {time, value}; 29918d3e65eSAxel Dörfler fBuffer.AddItem(item); 30018d3e65eSAxel Dörfler } 30118d3e65eSAxel Dörfler 30218d3e65eSAxel Dörfler 30318d3e65eSAxel Dörfler int64 30418d3e65eSAxel Dörfler DataHistory::ValueAt(bigtime_t time) 30518d3e65eSAxel Dörfler { 30651591198SAxel Dörfler int32 left = 0; 30751591198SAxel Dörfler int32 right = fBuffer.CountItems() - 1; 30851591198SAxel Dörfler data_item* item = NULL; 30951591198SAxel Dörfler 31051591198SAxel Dörfler while (left <= right) { 31151591198SAxel Dörfler int32 index = (left + right) / 2; 31251591198SAxel Dörfler item = fBuffer.ItemAt(index); 31351591198SAxel Dörfler 31451591198SAxel Dörfler if (item->time > time) { 31551591198SAxel Dörfler // search in left part 31651591198SAxel Dörfler right = index - 1; 31751591198SAxel Dörfler } else { 31884e23a5dSAxel Dörfler data_item* nextItem = fBuffer.ItemAt(index + 1); 31984e23a5dSAxel Dörfler if (nextItem == NULL) 32084e23a5dSAxel Dörfler return item->value; 32184e23a5dSAxel Dörfler if (nextItem->time > time) { 32251591198SAxel Dörfler // found item 32384e23a5dSAxel Dörfler int64 value = item->value; 32484e23a5dSAxel Dörfler value += int64(double(nextItem->value - value) 32584e23a5dSAxel Dörfler / (nextItem->time - item->time) * (time - item->time)); 326*8e26f387SAxel Dörfler return value; 32751591198SAxel Dörfler } 32851591198SAxel Dörfler 32951591198SAxel Dörfler // search in right part 33051591198SAxel Dörfler left = index + 1; 33151591198SAxel Dörfler } 33251591198SAxel Dörfler } 33318d3e65eSAxel Dörfler 33418d3e65eSAxel Dörfler return 0; 33518d3e65eSAxel Dörfler } 33618d3e65eSAxel Dörfler 33718d3e65eSAxel Dörfler 33818d3e65eSAxel Dörfler int64 33918d3e65eSAxel Dörfler DataHistory::MaximumValue() const 34018d3e65eSAxel Dörfler { 34151591198SAxel Dörfler if (fScale != NULL) 34251591198SAxel Dörfler return fScale->MaximumValue(); 34351591198SAxel Dörfler 34418d3e65eSAxel Dörfler return fMaximumValue; 34518d3e65eSAxel Dörfler } 34618d3e65eSAxel Dörfler 34718d3e65eSAxel Dörfler 34818d3e65eSAxel Dörfler int64 34918d3e65eSAxel Dörfler DataHistory::MinimumValue() const 35018d3e65eSAxel Dörfler { 35151591198SAxel Dörfler if (fScale != NULL) 35251591198SAxel Dörfler return fScale->MinimumValue(); 35351591198SAxel Dörfler 35418d3e65eSAxel Dörfler return fMinimumValue; 35518d3e65eSAxel Dörfler } 35618d3e65eSAxel Dörfler 35718d3e65eSAxel Dörfler 35818d3e65eSAxel Dörfler bigtime_t 35918d3e65eSAxel Dörfler DataHistory::Start() const 36018d3e65eSAxel Dörfler { 36118d3e65eSAxel Dörfler if (fBuffer.CountItems() == 0) 36218d3e65eSAxel Dörfler return 0; 36318d3e65eSAxel Dörfler 36418d3e65eSAxel Dörfler return fBuffer.ItemAt(0)->time; 36518d3e65eSAxel Dörfler } 36618d3e65eSAxel Dörfler 36718d3e65eSAxel Dörfler 36818d3e65eSAxel Dörfler bigtime_t 36918d3e65eSAxel Dörfler DataHistory::End() const 37018d3e65eSAxel Dörfler { 37118d3e65eSAxel Dörfler if (fBuffer.CountItems() == 0) 37218d3e65eSAxel Dörfler return 0; 37318d3e65eSAxel Dörfler 37418d3e65eSAxel Dörfler return fBuffer.ItemAt(fBuffer.CountItems() - 1)->time; 37518d3e65eSAxel Dörfler } 37618d3e65eSAxel Dörfler 37718d3e65eSAxel Dörfler 37818d3e65eSAxel Dörfler void 37918d3e65eSAxel Dörfler DataHistory::SetRefreshInterval(bigtime_t interval) 38018d3e65eSAxel Dörfler { 38118d3e65eSAxel Dörfler // TODO: adjust buffer size 38218d3e65eSAxel Dörfler } 38318d3e65eSAxel Dörfler 38418d3e65eSAxel Dörfler 38551591198SAxel Dörfler void 38651591198SAxel Dörfler DataHistory::SetScale(Scale* scale) 38751591198SAxel Dörfler { 38851591198SAxel Dörfler fScale = scale; 38951591198SAxel Dörfler } 39051591198SAxel Dörfler 39151591198SAxel Dörfler 39218d3e65eSAxel Dörfler // #pragma mark - 39318d3e65eSAxel Dörfler 39418d3e65eSAxel Dörfler 395dc1ffc79SFrançois Revol #ifdef __HAIKU__ 396065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::HistoryLayoutItem(ActivityView* parent) 397065e8de0SAxel Dörfler : 398065e8de0SAxel Dörfler fParent(parent), 399065e8de0SAxel Dörfler fFrame() 400065e8de0SAxel Dörfler { 401065e8de0SAxel Dörfler } 402065e8de0SAxel Dörfler 403065e8de0SAxel Dörfler 404065e8de0SAxel Dörfler bool 405065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::IsVisible() 406065e8de0SAxel Dörfler { 407065e8de0SAxel Dörfler return !fParent->IsHidden(fParent); 408065e8de0SAxel Dörfler } 409065e8de0SAxel Dörfler 410065e8de0SAxel Dörfler 411065e8de0SAxel Dörfler void 412065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::SetVisible(bool visible) 413065e8de0SAxel Dörfler { 414065e8de0SAxel Dörfler // not allowed 415065e8de0SAxel Dörfler } 416065e8de0SAxel Dörfler 417065e8de0SAxel Dörfler 418065e8de0SAxel Dörfler BRect 419065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::Frame() 420065e8de0SAxel Dörfler { 421065e8de0SAxel Dörfler return fFrame; 422065e8de0SAxel Dörfler } 423065e8de0SAxel Dörfler 424065e8de0SAxel Dörfler 425065e8de0SAxel Dörfler void 426065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::SetFrame(BRect frame) 427065e8de0SAxel Dörfler { 428065e8de0SAxel Dörfler fFrame = frame; 429065e8de0SAxel Dörfler fParent->_UpdateFrame(); 430065e8de0SAxel Dörfler } 431065e8de0SAxel Dörfler 432065e8de0SAxel Dörfler 433065e8de0SAxel Dörfler BView* 434065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::View() 435065e8de0SAxel Dörfler { 436065e8de0SAxel Dörfler return fParent; 437065e8de0SAxel Dörfler } 438065e8de0SAxel Dörfler 439065e8de0SAxel Dörfler 440065e8de0SAxel Dörfler BSize 441065e8de0SAxel Dörfler ActivityView::HistoryLayoutItem::BasePreferredSize() 442065e8de0SAxel Dörfler { 443065e8de0SAxel Dörfler BSize size(BaseMaxSize()); 444065e8de0SAxel Dörfler return size; 445065e8de0SAxel Dörfler } 446065e8de0SAxel Dörfler 447065e8de0SAxel Dörfler 448065e8de0SAxel Dörfler // #pragma mark - 449065e8de0SAxel Dörfler 450065e8de0SAxel Dörfler 451065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::LegendLayoutItem(ActivityView* parent) 452065e8de0SAxel Dörfler : 453065e8de0SAxel Dörfler fParent(parent), 454065e8de0SAxel Dörfler fFrame() 455065e8de0SAxel Dörfler { 456065e8de0SAxel Dörfler } 457065e8de0SAxel Dörfler 458065e8de0SAxel Dörfler 459065e8de0SAxel Dörfler bool 460065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::IsVisible() 461065e8de0SAxel Dörfler { 462065e8de0SAxel Dörfler return !fParent->IsHidden(fParent); 463065e8de0SAxel Dörfler } 464065e8de0SAxel Dörfler 465065e8de0SAxel Dörfler 466065e8de0SAxel Dörfler void 467065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::SetVisible(bool visible) 468065e8de0SAxel Dörfler { 469065e8de0SAxel Dörfler // not allowed 470065e8de0SAxel Dörfler } 471065e8de0SAxel Dörfler 472065e8de0SAxel Dörfler 473065e8de0SAxel Dörfler BRect 474065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::Frame() 475065e8de0SAxel Dörfler { 476065e8de0SAxel Dörfler return fFrame; 477065e8de0SAxel Dörfler } 478065e8de0SAxel Dörfler 479065e8de0SAxel Dörfler 480065e8de0SAxel Dörfler void 481065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::SetFrame(BRect frame) 482065e8de0SAxel Dörfler { 483065e8de0SAxel Dörfler fFrame = frame; 484065e8de0SAxel Dörfler fParent->_UpdateFrame(); 485065e8de0SAxel Dörfler } 486065e8de0SAxel Dörfler 487065e8de0SAxel Dörfler 488065e8de0SAxel Dörfler BView* 489065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::View() 490065e8de0SAxel Dörfler { 491065e8de0SAxel Dörfler return fParent; 492065e8de0SAxel Dörfler } 493065e8de0SAxel Dörfler 494065e8de0SAxel Dörfler 495065e8de0SAxel Dörfler BSize 496065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::BaseMinSize() 497065e8de0SAxel Dörfler { 498065e8de0SAxel Dörfler // TODO: Cache the info. Might be too expensive for this call. 499065e8de0SAxel Dörfler BSize size; 500065e8de0SAxel Dörfler size.width = 80; 501065e8de0SAxel Dörfler size.height = fParent->_LegendHeight(); 502065e8de0SAxel Dörfler 503065e8de0SAxel Dörfler return size; 504065e8de0SAxel Dörfler } 505065e8de0SAxel Dörfler 506065e8de0SAxel Dörfler 507065e8de0SAxel Dörfler BSize 508065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::BaseMaxSize() 509065e8de0SAxel Dörfler { 510065e8de0SAxel Dörfler BSize size(BaseMinSize()); 511065e8de0SAxel Dörfler size.width = B_SIZE_UNLIMITED; 512065e8de0SAxel Dörfler return size; 513065e8de0SAxel Dörfler } 514065e8de0SAxel Dörfler 515065e8de0SAxel Dörfler 516065e8de0SAxel Dörfler BSize 517065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::BasePreferredSize() 518065e8de0SAxel Dörfler { 519065e8de0SAxel Dörfler BSize size(BaseMinSize()); 520065e8de0SAxel Dörfler return size; 521065e8de0SAxel Dörfler } 522065e8de0SAxel Dörfler 523065e8de0SAxel Dörfler 524065e8de0SAxel Dörfler BAlignment 525065e8de0SAxel Dörfler ActivityView::LegendLayoutItem::BaseAlignment() 526065e8de0SAxel Dörfler { 527065e8de0SAxel Dörfler return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); 528065e8de0SAxel Dörfler } 529dc1ffc79SFrançois Revol #endif 530065e8de0SAxel Dörfler 531065e8de0SAxel Dörfler 532065e8de0SAxel Dörfler // #pragma mark - 533065e8de0SAxel Dörfler 534065e8de0SAxel Dörfler 53518d3e65eSAxel Dörfler ActivityView::ActivityView(BRect frame, const char* name, 5363a4a2141SAxel Dörfler const BMessage* settings, uint32 resizingMode) 53718d3e65eSAxel Dörfler : BView(frame, name, resizingMode, 538d4216445SAxel Dörfler B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS), 539d4216445SAxel Dörfler fSourcesLock("data sources") 54018d3e65eSAxel Dörfler { 5413a4a2141SAxel Dörfler _Init(settings); 5423a4a2141SAxel Dörfler 5433a4a2141SAxel Dörfler BRect rect(Bounds()); 5443a4a2141SAxel Dörfler rect.top = rect.bottom - 7; 5453a4a2141SAxel Dörfler rect.left = rect.right - 7; 5463a4a2141SAxel Dörfler BDragger* dragger = new BDragger(rect, this, 5473a4a2141SAxel Dörfler B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); 5483a4a2141SAxel Dörfler AddChild(dragger); 5493a4a2141SAxel Dörfler } 5503a4a2141SAxel Dörfler 5513a4a2141SAxel Dörfler 5523a4a2141SAxel Dörfler ActivityView::ActivityView(const char* name, const BMessage* settings) 553cbd4bc95SFrançois Revol #ifdef __HAIKU__ 554d4216445SAxel Dörfler : BView(name, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS), 555cbd4bc95SFrançois Revol #else 556d4216445SAxel Dörfler : BView(BRect(0,0,300,200), name, B_FOLLOW_NONE, 557d4216445SAxel Dörfler B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS), 558cbd4bc95SFrançois Revol #endif 559d4216445SAxel Dörfler fSourcesLock("data sources") 5603a4a2141SAxel Dörfler { 56179cbd226SFrançois Revol SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 5629c89c450SAxel Dörfler 5633a4a2141SAxel Dörfler _Init(settings); 56418d3e65eSAxel Dörfler 56518d3e65eSAxel Dörfler BRect rect(Bounds()); 56618d3e65eSAxel Dörfler rect.top = rect.bottom - 7; 56718d3e65eSAxel Dörfler rect.left = rect.right - 7; 56818d3e65eSAxel Dörfler BDragger* dragger = new BDragger(rect, this, 56918d3e65eSAxel Dörfler B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); 57018d3e65eSAxel Dörfler AddChild(dragger); 57118d3e65eSAxel Dörfler } 57218d3e65eSAxel Dörfler 57318d3e65eSAxel Dörfler 57418d3e65eSAxel Dörfler ActivityView::ActivityView(BMessage* archive) 57518d3e65eSAxel Dörfler : BView(archive) 57618d3e65eSAxel Dörfler { 57718d3e65eSAxel Dörfler _Init(archive); 57818d3e65eSAxel Dörfler } 57918d3e65eSAxel Dörfler 58018d3e65eSAxel Dörfler 58118d3e65eSAxel Dörfler ActivityView::~ActivityView() 58218d3e65eSAxel Dörfler { 5833a4a2141SAxel Dörfler delete fOffscreen; 58474158bb4SFrançois Revol delete fSystemInfoHandler; 58518d3e65eSAxel Dörfler } 58618d3e65eSAxel Dörfler 58718d3e65eSAxel Dörfler 58818d3e65eSAxel Dörfler void 58918d3e65eSAxel Dörfler ActivityView::_Init(const BMessage* settings) 59018d3e65eSAxel Dörfler { 5919c89c450SAxel Dörfler fHistoryBackgroundColor = (rgb_color){255, 255, 240}; 5929c89c450SAxel Dörfler fLegendBackgroundColor = LowColor(); 5939c89c450SAxel Dörfler // the low color is restored by the BView unarchiving 5943a4a2141SAxel Dörfler fOffscreen = NULL; 595dc1ffc79SFrançois Revol #ifdef __HAIKU__ 596065e8de0SAxel Dörfler fHistoryLayoutItem = NULL; 597065e8de0SAxel Dörfler fLegendLayoutItem = NULL; 598dc1ffc79SFrançois Revol #endif 5993a4a2141SAxel Dörfler SetViewColor(B_TRANSPARENT_COLOR); 60018d3e65eSAxel Dörfler 60118d3e65eSAxel Dörfler fRefreshInterval = kInitialRefreshInterval; 60218d3e65eSAxel Dörfler fLastRefresh = 0; 60318d3e65eSAxel Dörfler fDrawResolution = 1; 60451591198SAxel Dörfler fZooming = false; 60518d3e65eSAxel Dörfler 60674158bb4SFrançois Revol fSystemInfoHandler = new SystemInfoHandler; 60774158bb4SFrançois Revol 6083a4a2141SAxel Dörfler if (settings == NULL 6093a4a2141SAxel Dörfler || settings->FindBool("show legend", &fShowLegend) != B_OK) 6103a4a2141SAxel Dörfler fShowLegend = true; 6113a4a2141SAxel Dörfler 61251591198SAxel Dörfler if (settings == NULL) 6133a4a2141SAxel Dörfler return; 6143a4a2141SAxel Dörfler 6159c89c450SAxel Dörfler ssize_t colorLength; 61679cbd226SFrançois Revol rgb_color *color; 6179c89c450SAxel Dörfler if (settings->FindData("history background color", B_RGB_COLOR_TYPE, 6189c89c450SAxel Dörfler (const void **)&color, &colorLength) == B_OK 6199c89c450SAxel Dörfler && colorLength == sizeof(rgb_color)) 6209c89c450SAxel Dörfler fHistoryBackgroundColor = *color; 62179cbd226SFrançois Revol 6223a4a2141SAxel Dörfler const char* name; 6233a4a2141SAxel Dörfler for (int32 i = 0; settings->FindString("source", i, &name) == B_OK; i++) { 6241201d52eSAxel Dörfler AddDataSource(DataSource::FindSource(name), settings); 6253a4a2141SAxel Dörfler } 62618d3e65eSAxel Dörfler } 62718d3e65eSAxel Dörfler 62818d3e65eSAxel Dörfler 62918d3e65eSAxel Dörfler status_t 63018d3e65eSAxel Dörfler ActivityView::Archive(BMessage* into, bool deep) const 63118d3e65eSAxel Dörfler { 63218d3e65eSAxel Dörfler status_t status; 63318d3e65eSAxel Dörfler 63418d3e65eSAxel Dörfler status = BView::Archive(into, deep); 63518d3e65eSAxel Dörfler if (status < B_OK) 63618d3e65eSAxel Dörfler return status; 63718d3e65eSAxel Dörfler 63818d3e65eSAxel Dörfler status = into->AddString("add_on", kSignature); 63918d3e65eSAxel Dörfler if (status < B_OK) 64018d3e65eSAxel Dörfler return status; 64118d3e65eSAxel Dörfler 64218d3e65eSAxel Dörfler status = SaveState(*into); 64318d3e65eSAxel Dörfler if (status < B_OK) 64418d3e65eSAxel Dörfler return status; 64518d3e65eSAxel Dörfler 64618d3e65eSAxel Dörfler return B_OK; 64718d3e65eSAxel Dörfler } 64818d3e65eSAxel Dörfler 64918d3e65eSAxel Dörfler 65018d3e65eSAxel Dörfler BArchivable* 65118d3e65eSAxel Dörfler ActivityView::Instantiate(BMessage* archive) 65218d3e65eSAxel Dörfler { 65318d3e65eSAxel Dörfler if (!validate_instantiation(archive, "ActivityView")) 65418d3e65eSAxel Dörfler return NULL; 65518d3e65eSAxel Dörfler 65618d3e65eSAxel Dörfler return new ActivityView(archive); 65718d3e65eSAxel Dörfler } 65818d3e65eSAxel Dörfler 65918d3e65eSAxel Dörfler 66018d3e65eSAxel Dörfler status_t 66118d3e65eSAxel Dörfler ActivityView::SaveState(BMessage& state) const 66218d3e65eSAxel Dörfler { 6633a4a2141SAxel Dörfler status_t status = state.AddBool("show legend", fShowLegend); 6643a4a2141SAxel Dörfler if (status != B_OK) 6653a4a2141SAxel Dörfler return status; 6663a4a2141SAxel Dörfler 6679c89c450SAxel Dörfler status = state.AddData("history background color", B_RGB_COLOR_TYPE, 6689c89c450SAxel Dörfler &fHistoryBackgroundColor, sizeof(rgb_color)); 66979cbd226SFrançois Revol if (status != B_OK) 67079cbd226SFrançois Revol return status; 67179cbd226SFrançois Revol 6723a4a2141SAxel Dörfler for (int32 i = 0; i < fSources.CountItems(); i++) { 6733a4a2141SAxel Dörfler DataSource* source = fSources.ItemAt(i); 6743a4a2141SAxel Dörfler 6753a4a2141SAxel Dörfler if (!source->PerCPU() || source->CPU() == 0) 6763a4a2141SAxel Dörfler status = state.AddString("source", source->Name()); 6773a4a2141SAxel Dörfler if (status != B_OK) 6783a4a2141SAxel Dörfler return status; 6793a4a2141SAxel Dörfler 6809c89c450SAxel Dörfler BString name = source->Name(); 6819c89c450SAxel Dörfler name << " color"; 6829c89c450SAxel Dörfler rgb_color color = source->Color(); 6839c89c450SAxel Dörfler state.AddData(name.String(), B_RGB_COLOR_TYPE, &color, 6849c89c450SAxel Dörfler sizeof(rgb_color)); 6853a4a2141SAxel Dörfler } 6863a4a2141SAxel Dörfler return B_OK; 68718d3e65eSAxel Dörfler } 68818d3e65eSAxel Dörfler 68918d3e65eSAxel Dörfler 69051591198SAxel Dörfler Scale* 69151591198SAxel Dörfler ActivityView::_ScaleFor(scale_type type) 69251591198SAxel Dörfler { 69351591198SAxel Dörfler if (type == kNoScale) 69451591198SAxel Dörfler return NULL; 69551591198SAxel Dörfler 69651591198SAxel Dörfler std::map<scale_type, ::Scale*>::iterator iterator = fScales.find(type); 69751591198SAxel Dörfler if (iterator != fScales.end()) 69851591198SAxel Dörfler return iterator->second; 69951591198SAxel Dörfler 70051591198SAxel Dörfler // add new scale 70151591198SAxel Dörfler ::Scale* scale = new ::Scale(type); 70251591198SAxel Dörfler fScales[type] = scale; 70351591198SAxel Dörfler 70451591198SAxel Dörfler return scale; 70551591198SAxel Dörfler } 70651591198SAxel Dörfler 70751591198SAxel Dörfler 708dc1ffc79SFrançois Revol #ifdef __HAIKU__ 709065e8de0SAxel Dörfler BLayoutItem* 710065e8de0SAxel Dörfler ActivityView::CreateHistoryLayoutItem() 711065e8de0SAxel Dörfler { 712065e8de0SAxel Dörfler if (fHistoryLayoutItem == NULL) 713065e8de0SAxel Dörfler fHistoryLayoutItem = new HistoryLayoutItem(this); 714065e8de0SAxel Dörfler 715065e8de0SAxel Dörfler return fHistoryLayoutItem; 716065e8de0SAxel Dörfler } 717065e8de0SAxel Dörfler 718065e8de0SAxel Dörfler 719065e8de0SAxel Dörfler BLayoutItem* 720065e8de0SAxel Dörfler ActivityView::CreateLegendLayoutItem() 721065e8de0SAxel Dörfler { 722065e8de0SAxel Dörfler if (fLegendLayoutItem == NULL) 723065e8de0SAxel Dörfler fLegendLayoutItem = new LegendLayoutItem(this); 724065e8de0SAxel Dörfler 725065e8de0SAxel Dörfler return fLegendLayoutItem; 726065e8de0SAxel Dörfler } 727dc1ffc79SFrançois Revol #endif 728065e8de0SAxel Dörfler 7299c89c450SAxel Dörfler 73018d3e65eSAxel Dörfler DataSource* 7313a4a2141SAxel Dörfler ActivityView::FindDataSource(const DataSource* search) 73218d3e65eSAxel Dörfler { 733d4216445SAxel Dörfler BAutolock _(fSourcesLock); 734d4216445SAxel Dörfler 73518d3e65eSAxel Dörfler for (int32 i = fSources.CountItems(); i-- > 0;) { 73618d3e65eSAxel Dörfler DataSource* source = fSources.ItemAt(i); 7373a4a2141SAxel Dörfler if (!strcmp(source->Name(), search->Name())) 73818d3e65eSAxel Dörfler return source; 73918d3e65eSAxel Dörfler } 74018d3e65eSAxel Dörfler 74118d3e65eSAxel Dörfler return NULL; 74218d3e65eSAxel Dörfler } 74318d3e65eSAxel Dörfler 74418d3e65eSAxel Dörfler 74518d3e65eSAxel Dörfler status_t 7469c89c450SAxel Dörfler ActivityView::AddDataSource(const DataSource* source, const BMessage* state) 74718d3e65eSAxel Dörfler { 7483a4a2141SAxel Dörfler if (source == NULL) 7493a4a2141SAxel Dörfler return B_BAD_VALUE; 7503a4a2141SAxel Dörfler 751d4216445SAxel Dörfler BAutolock _(fSourcesLock); 752d4216445SAxel Dörfler 753*8e26f387SAxel Dörfler // Search for the correct insert spot to maintain the order of the sources 7543a4a2141SAxel Dörfler int32 insert = DataSource::IndexOf(source); 7553a4a2141SAxel Dörfler for (int32 i = 0; i < fSources.CountItems() && i < insert; i++) { 7563a4a2141SAxel Dörfler DataSource* before = fSources.ItemAt(i); 7573a4a2141SAxel Dörfler if (DataSource::IndexOf(before) > insert) { 7583a4a2141SAxel Dörfler insert = i; 7593a4a2141SAxel Dörfler break; 7603a4a2141SAxel Dörfler } 7613a4a2141SAxel Dörfler } 7623a4a2141SAxel Dörfler if (insert > fSources.CountItems()) 7633a4a2141SAxel Dörfler insert = fSources.CountItems(); 7643a4a2141SAxel Dörfler 765*8e26f387SAxel Dörfler // Generate DataHistory and ViewHistory objects for the source 766*8e26f387SAxel Dörfler // (one might need one history per CPU) 767*8e26f387SAxel Dörfler 7683a4a2141SAxel Dörfler uint32 count = 1; 7693a4a2141SAxel Dörfler if (source->PerCPU()) { 7703a4a2141SAxel Dörfler SystemInfo info; 7713a4a2141SAxel Dörfler count = info.CPUCount(); 7723a4a2141SAxel Dörfler } 7733a4a2141SAxel Dörfler 7743a4a2141SAxel Dörfler for (uint32 i = 0; i < count; i++) { 77518d3e65eSAxel Dörfler DataHistory* values = new(std::nothrow) DataHistory(10 * 60000000LL, 7761bb87bd0SAxel Dörfler RefreshInterval()); 777*8e26f387SAxel Dörfler ListAddDeleter<DataHistory> valuesDeleter(fValues, values, insert); 7783a4a2141SAxel Dörfler 779*8e26f387SAxel Dörfler ViewHistory* viewValues = new(std::nothrow) ViewHistory; 780*8e26f387SAxel Dörfler ListAddDeleter<ViewHistory> viewValuesDeleter(fViewValues, viewValues, 781*8e26f387SAxel Dörfler insert); 782*8e26f387SAxel Dörfler 783*8e26f387SAxel Dörfler if (valuesDeleter.Failed() || viewValuesDeleter.Failed()) 78418d3e65eSAxel Dörfler return B_NO_MEMORY; 78518d3e65eSAxel Dörfler 78651591198SAxel Dörfler values->SetScale(_ScaleFor(source->ScaleType())); 78751591198SAxel Dörfler 7883a4a2141SAxel Dörfler DataSource* copy; 7893a4a2141SAxel Dörfler if (source->PerCPU()) 7903a4a2141SAxel Dörfler copy = source->CopyForCPU(i); 7913a4a2141SAxel Dörfler else 7923a4a2141SAxel Dörfler copy = source->Copy(); 7933a4a2141SAxel Dörfler 794*8e26f387SAxel Dörfler ListAddDeleter<DataSource> sourceDeleter(fSources, copy, insert); 795*8e26f387SAxel Dörfler if (sourceDeleter.Failed()) 796*8e26f387SAxel Dörfler return B_NO_MEMORY; 797*8e26f387SAxel Dörfler 7989c89c450SAxel Dörfler BString colorName = source->Name(); 7999c89c450SAxel Dörfler colorName << " color"; 8009c89c450SAxel Dörfler if (state != NULL) { 8019c89c450SAxel Dörfler const rgb_color* color = NULL; 8029c89c450SAxel Dörfler ssize_t colorLength; 8039c89c450SAxel Dörfler if (state->FindData(colorName.String(), B_RGB_COLOR_TYPE, i, 8049c89c450SAxel Dörfler (const void**)&color, &colorLength) == B_OK 8059c89c450SAxel Dörfler && colorLength == sizeof(rgb_color)) 8069c89c450SAxel Dörfler copy->SetColor(*color); 8079c89c450SAxel Dörfler } 8089c89c450SAxel Dörfler 809*8e26f387SAxel Dörfler valuesDeleter.Detach(); 810*8e26f387SAxel Dörfler viewValuesDeleter.Detach(); 811*8e26f387SAxel Dörfler sourceDeleter.Detach(); 8123a4a2141SAxel Dörfler } 81318d3e65eSAxel Dörfler 814dc1ffc79SFrançois Revol #ifdef __HAIKU__ 815065e8de0SAxel Dörfler InvalidateLayout(); 816dc1ffc79SFrançois Revol #endif 81718d3e65eSAxel Dörfler return B_OK; 81818d3e65eSAxel Dörfler } 81918d3e65eSAxel Dörfler 82018d3e65eSAxel Dörfler 82118d3e65eSAxel Dörfler status_t 8223a4a2141SAxel Dörfler ActivityView::RemoveDataSource(const DataSource* remove) 82318d3e65eSAxel Dörfler { 824065e8de0SAxel Dörfler bool removed = false; 825065e8de0SAxel Dörfler 826d4216445SAxel Dörfler BAutolock _(fSourcesLock); 827d4216445SAxel Dörfler 8283a4a2141SAxel Dörfler while (true) { 8293a4a2141SAxel Dörfler DataSource* source = FindDataSource(remove); 830acef7474SFrançois Revol //debug_printf("SEARCH %s, found %p\n", remove->Name(), source); 831065e8de0SAxel Dörfler if (source == NULL) { 832065e8de0SAxel Dörfler if (removed) 833065e8de0SAxel Dörfler break; 834065e8de0SAxel Dörfler return B_ENTRY_NOT_FOUND; 835065e8de0SAxel Dörfler } 8363a4a2141SAxel Dörfler 83718d3e65eSAxel Dörfler int32 index = fSources.IndexOf(source); 83818d3e65eSAxel Dörfler if (index < 0) 83918d3e65eSAxel Dörfler return B_ENTRY_NOT_FOUND; 84018d3e65eSAxel Dörfler 84118d3e65eSAxel Dörfler fSources.RemoveItemAt(index); 84218d3e65eSAxel Dörfler delete source; 84318d3e65eSAxel Dörfler DataHistory* values = fValues.RemoveItemAt(index); 84418d3e65eSAxel Dörfler delete values; 845065e8de0SAxel Dörfler removed = true; 8463a4a2141SAxel Dörfler } 84718d3e65eSAxel Dörfler 848dc1ffc79SFrançois Revol #ifdef __HAIKU__ 849065e8de0SAxel Dörfler InvalidateLayout(); 850dc1ffc79SFrançois Revol #endif 85118d3e65eSAxel Dörfler return B_OK; 85218d3e65eSAxel Dörfler } 85318d3e65eSAxel Dörfler 85418d3e65eSAxel Dörfler 85518d3e65eSAxel Dörfler void 85618d3e65eSAxel Dörfler ActivityView::RemoveAllDataSources() 85718d3e65eSAxel Dörfler { 858d4216445SAxel Dörfler BAutolock _(fSourcesLock); 859d4216445SAxel Dörfler 86018d3e65eSAxel Dörfler fSources.MakeEmpty(); 86118d3e65eSAxel Dörfler fValues.MakeEmpty(); 86218d3e65eSAxel Dörfler } 86318d3e65eSAxel Dörfler 86418d3e65eSAxel Dörfler 86518d3e65eSAxel Dörfler void 86618d3e65eSAxel Dörfler ActivityView::AttachedToWindow() 86718d3e65eSAxel Dörfler { 86874158bb4SFrançois Revol Looper()->AddHandler(fSystemInfoHandler); 8696f6ba875SAxel Dörfler fSystemInfoHandler->StartWatching(); 8706f6ba875SAxel Dörfler 871d4216445SAxel Dörfler fRefreshSem = create_sem(0, "refresh sem"); 872d4216445SAxel Dörfler fRefreshThread = spawn_thread(&_RefreshThread, "source refresh", 873*8e26f387SAxel Dörfler B_URGENT_DISPLAY_PRIORITY, this); 874d4216445SAxel Dörfler resume_thread(fRefreshThread); 8753a4a2141SAxel Dörfler 8763a4a2141SAxel Dörfler FrameResized(Bounds().Width(), Bounds().Height()); 87718d3e65eSAxel Dörfler } 87818d3e65eSAxel Dörfler 87918d3e65eSAxel Dörfler 88018d3e65eSAxel Dörfler void 88118d3e65eSAxel Dörfler ActivityView::DetachedFromWindow() 88218d3e65eSAxel Dörfler { 8836f6ba875SAxel Dörfler fSystemInfoHandler->StopWatching(); 88474158bb4SFrançois Revol Looper()->RemoveHandler(fSystemInfoHandler); 8856f6ba875SAxel Dörfler 886d4216445SAxel Dörfler delete_sem(fRefreshSem); 887d4216445SAxel Dörfler wait_for_thread(fRefreshThread, NULL); 88818d3e65eSAxel Dörfler } 88918d3e65eSAxel Dörfler 89018d3e65eSAxel Dörfler 891cbd4bc95SFrançois Revol #ifdef __HAIKU__ 8923a4a2141SAxel Dörfler BSize 8933a4a2141SAxel Dörfler ActivityView::MinSize() 8943a4a2141SAxel Dörfler { 8953a4a2141SAxel Dörfler BSize size(32, 32); 8963a4a2141SAxel Dörfler if (fShowLegend) 8979c89c450SAxel Dörfler size.height = _LegendHeight(); 8983a4a2141SAxel Dörfler 8993a4a2141SAxel Dörfler return size; 9003a4a2141SAxel Dörfler } 901cbd4bc95SFrançois Revol #endif 9023a4a2141SAxel Dörfler 9033a4a2141SAxel Dörfler 90418d3e65eSAxel Dörfler void 90518d3e65eSAxel Dörfler ActivityView::FrameResized(float /*width*/, float /*height*/) 90618d3e65eSAxel Dörfler { 9073a4a2141SAxel Dörfler _UpdateOffscreenBitmap(); 9083a4a2141SAxel Dörfler } 9093a4a2141SAxel Dörfler 9103a4a2141SAxel Dörfler 9113a4a2141SAxel Dörfler void 9129c89c450SAxel Dörfler ActivityView::_UpdateOffscreenBitmap() 9133a4a2141SAxel Dörfler { 9143a4a2141SAxel Dörfler BRect frame = _HistoryFrame(); 9159c89c450SAxel Dörfler if (fOffscreen != NULL && frame == fOffscreen->Bounds()) 9163a4a2141SAxel Dörfler return; 9173a4a2141SAxel Dörfler 9183a4a2141SAxel Dörfler delete fOffscreen; 9193a4a2141SAxel Dörfler 9203a4a2141SAxel Dörfler // create offscreen bitmap 9213a4a2141SAxel Dörfler 9223a4a2141SAxel Dörfler fOffscreen = new(std::nothrow) BBitmap(frame, B_BITMAP_ACCEPTS_VIEWS, 9233a4a2141SAxel Dörfler B_RGB32); 9243a4a2141SAxel Dörfler if (fOffscreen == NULL || fOffscreen->InitCheck() != B_OK) { 9253a4a2141SAxel Dörfler delete fOffscreen; 9263a4a2141SAxel Dörfler fOffscreen = NULL; 9273a4a2141SAxel Dörfler return; 9283a4a2141SAxel Dörfler } 9293a4a2141SAxel Dörfler 9303a4a2141SAxel Dörfler BView* view = new BView(frame, NULL, B_FOLLOW_NONE, B_SUBPIXEL_PRECISE); 9319c89c450SAxel Dörfler view->SetViewColor(fHistoryBackgroundColor); 9323a4a2141SAxel Dörfler view->SetLowColor(view->ViewColor()); 9333a4a2141SAxel Dörfler fOffscreen->AddChild(view); 93418d3e65eSAxel Dörfler } 93518d3e65eSAxel Dörfler 93618d3e65eSAxel Dörfler 9379c89c450SAxel Dörfler BView* 9389c89c450SAxel Dörfler ActivityView::_OffscreenView() 9399c89c450SAxel Dörfler { 9409c89c450SAxel Dörfler if (fOffscreen == NULL) 9419c89c450SAxel Dörfler return NULL; 9429c89c450SAxel Dörfler 9439c89c450SAxel Dörfler return fOffscreen->ChildAt(0); 9449c89c450SAxel Dörfler } 9459c89c450SAxel Dörfler 9469c89c450SAxel Dörfler 94718d3e65eSAxel Dörfler void 94818d3e65eSAxel Dörfler ActivityView::MouseDown(BPoint where) 94918d3e65eSAxel Dörfler { 95051591198SAxel Dörfler int32 buttons = B_SECONDARY_MOUSE_BUTTON; 95151591198SAxel Dörfler if (Looper() != NULL && Looper()->CurrentMessage() != NULL) 95218d3e65eSAxel Dörfler Looper()->CurrentMessage()->FindInt32("buttons", &buttons); 95351591198SAxel Dörfler 95451591198SAxel Dörfler if (buttons == B_PRIMARY_MOUSE_BUTTON) { 95551591198SAxel Dörfler fZoomPoint = where; 95651591198SAxel Dörfler fOriginalResolution = fDrawResolution; 95751591198SAxel Dörfler fZooming = true; 958*8e26f387SAxel Dörfler SetMouseEventMask(B_POINTER_EVENTS); 95951591198SAxel Dörfler return; 96018d3e65eSAxel Dörfler } 96118d3e65eSAxel Dörfler 96218d3e65eSAxel Dörfler BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING, false, false); 96318d3e65eSAxel Dörfler menu->SetFont(be_plain_font); 9643a4a2141SAxel Dörfler 96543eda1cdSAxel Dörfler BMenu* additionalMenu = new BMenu("Additional Items"); 966dc1ffc79SFrançois Revol additionalMenu->SetFont(be_plain_font); 967dc1ffc79SFrançois Revol 9683a4a2141SAxel Dörfler SystemInfo info; 96918d3e65eSAxel Dörfler BMenuItem* item; 97018d3e65eSAxel Dörfler 97118d3e65eSAxel Dörfler for (int32 i = 0; i < DataSource::CountSources(); i++) { 97218d3e65eSAxel Dörfler const DataSource* source = DataSource::SourceAt(i); 97318d3e65eSAxel Dörfler 9743a4a2141SAxel Dörfler if (source->MultiCPUOnly() && info.CPUCount() == 1) 9753a4a2141SAxel Dörfler continue; 9763a4a2141SAxel Dörfler 97718d3e65eSAxel Dörfler BMessage* message = new BMessage(kMsgToggleDataSource); 97818d3e65eSAxel Dörfler message->AddInt32("index", i); 97918d3e65eSAxel Dörfler 9803a4a2141SAxel Dörfler item = new BMenuItem(source->Name(), message); 9813a4a2141SAxel Dörfler if (FindDataSource(source)) 98218d3e65eSAxel Dörfler item->SetMarked(true); 98318d3e65eSAxel Dörfler 98443eda1cdSAxel Dörfler if (source->Primary()) 98518d3e65eSAxel Dörfler menu->AddItem(item); 98643eda1cdSAxel Dörfler else 98743eda1cdSAxel Dörfler additionalMenu->AddItem(item); 98818d3e65eSAxel Dörfler } 98918d3e65eSAxel Dörfler 99043eda1cdSAxel Dörfler menu->AddItem(new BMenuItem(additionalMenu)); 9913a4a2141SAxel Dörfler menu->AddSeparatorItem(); 9923a4a2141SAxel Dörfler menu->AddItem(new BMenuItem(fShowLegend ? "Hide Legend" : "Show Legend", 9933a4a2141SAxel Dörfler new BMessage(kMsgToggleLegend))); 9943a4a2141SAxel Dörfler 99518d3e65eSAxel Dörfler menu->SetTargetForItems(this); 996dc1ffc79SFrançois Revol additionalMenu->SetTargetForItems(this); 99718d3e65eSAxel Dörfler 9983f315b26SAxel Dörfler ActivityWindow* window = dynamic_cast<ActivityWindow*>(Window()); 9993f315b26SAxel Dörfler if (window != NULL && window->ActivityViewCount() > 1) { 10003f315b26SAxel Dörfler menu->AddSeparatorItem(); 10013f315b26SAxel Dörfler BMessage* message = new BMessage(kMsgRemoveView); 10023f315b26SAxel Dörfler message->AddPointer("view", this); 10033f315b26SAxel Dörfler menu->AddItem(item = new BMenuItem("Remove View", message)); 10043f315b26SAxel Dörfler item->SetTarget(window); 10053f315b26SAxel Dörfler } 10063f315b26SAxel Dörfler 100718d3e65eSAxel Dörfler ConvertToScreen(&where); 100818d3e65eSAxel Dörfler menu->Go(where, true, false, true); 100918d3e65eSAxel Dörfler } 101018d3e65eSAxel Dörfler 101118d3e65eSAxel Dörfler 101218d3e65eSAxel Dörfler void 101351591198SAxel Dörfler ActivityView::MouseUp(BPoint where) 101451591198SAxel Dörfler { 101551591198SAxel Dörfler fZooming = false; 101651591198SAxel Dörfler } 101751591198SAxel Dörfler 101851591198SAxel Dörfler 101951591198SAxel Dörfler void 102018d3e65eSAxel Dörfler ActivityView::MouseMoved(BPoint where, uint32 transit, 102118d3e65eSAxel Dörfler const BMessage* dragMessage) 102218d3e65eSAxel Dörfler { 102351591198SAxel Dörfler if (!fZooming) 102451591198SAxel Dörfler return; 102551591198SAxel Dörfler 102651591198SAxel Dörfler int32 shift = int32(where.x - fZoomPoint.x) / 25; 10271bb87bd0SAxel Dörfler int32 resolution; 102851591198SAxel Dörfler if (shift > 0) 10291bb87bd0SAxel Dörfler resolution = fOriginalResolution << shift; 103051591198SAxel Dörfler else 10311bb87bd0SAxel Dörfler resolution = fOriginalResolution >> -shift; 103251591198SAxel Dörfler 10331bb87bd0SAxel Dörfler _UpdateResolution(resolution); 103418d3e65eSAxel Dörfler } 103518d3e65eSAxel Dörfler 103618d3e65eSAxel Dörfler 103718d3e65eSAxel Dörfler void 103818d3e65eSAxel Dörfler ActivityView::MessageReceived(BMessage* message) 103918d3e65eSAxel Dörfler { 1040c28f8ea3SFrançois Revol // if a color is dropped, use it as background 1041c28f8ea3SFrançois Revol if (message->WasDropped()) { 1042c28f8ea3SFrançois Revol rgb_color* color; 1043c28f8ea3SFrançois Revol ssize_t size; 10441201d52eSAxel Dörfler if (message->FindData("RGBColor", B_RGB_COLOR_TYPE, 0, 10451201d52eSAxel Dörfler (const void**)&color, &size) == B_OK 10469c89c450SAxel Dörfler && size == sizeof(rgb_color)) { 10479c89c450SAxel Dörfler BPoint dropPoint = message->DropPoint(); 1048c28f8ea3SFrançois Revol ConvertFromScreen(&dropPoint); 10499c89c450SAxel Dörfler 1050c28f8ea3SFrançois Revol if (_HistoryFrame().Contains(dropPoint)) { 10519c89c450SAxel Dörfler fHistoryBackgroundColor = *color; 10529c89c450SAxel Dörfler Invalidate(_HistoryFrame()); 1053c28f8ea3SFrançois Revol } else { 10545f2f72a2SFrançois Revol // check each legend color box 1055d4216445SAxel Dörfler BAutolock _(fSourcesLock); 1056d4216445SAxel Dörfler 10575f2f72a2SFrançois Revol BRect legendFrame = _LegendFrame(); 10589c89c450SAxel Dörfler for (int32 i = 0; i < fSources.CountItems(); i++) { 10591201d52eSAxel Dörfler BRect frame = _LegendColorFrameAt(legendFrame, i); 10609c89c450SAxel Dörfler if (frame.Contains(dropPoint)) { 10615f2f72a2SFrançois Revol fSources.ItemAt(i)->SetColor(*color); 10629c89c450SAxel Dörfler Invalidate(_HistoryFrame()); 10631201d52eSAxel Dörfler Invalidate(frame); 10645f2f72a2SFrançois Revol return; 10655f2f72a2SFrançois Revol } 10665f2f72a2SFrançois Revol } 10679c89c450SAxel Dörfler 10689c89c450SAxel Dörfler if (dynamic_cast<ActivityMonitor*>(be_app) == NULL) { 10699c89c450SAxel Dörfler // allow background color change in the replicant only 10709c89c450SAxel Dörfler fLegendBackgroundColor = *color; 10711201d52eSAxel Dörfler SetLowColor(fLegendBackgroundColor); 10729c89c450SAxel Dörfler Invalidate(legendFrame); 10739c89c450SAxel Dörfler } 1074c28f8ea3SFrançois Revol } 1075c28f8ea3SFrançois Revol return; 1076c28f8ea3SFrançois Revol } 10779c89c450SAxel Dörfler } 10789c89c450SAxel Dörfler 107918d3e65eSAxel Dörfler switch (message->what) { 108018d3e65eSAxel Dörfler case B_ABOUT_REQUESTED: 108118d3e65eSAxel Dörfler ActivityMonitor::ShowAbout(); 108218d3e65eSAxel Dörfler break; 108318d3e65eSAxel Dörfler 10841bb87bd0SAxel Dörfler case kMsgUpdateResolution: 10851bb87bd0SAxel Dörfler { 10861bb87bd0SAxel Dörfler int32 resolution; 10871bb87bd0SAxel Dörfler if (message->FindInt32("resolution", &resolution) != B_OK) 10881bb87bd0SAxel Dörfler break; 10891bb87bd0SAxel Dörfler 10901bb87bd0SAxel Dörfler _UpdateResolution(resolution, false); 10911bb87bd0SAxel Dörfler break; 10921bb87bd0SAxel Dörfler } 10931bb87bd0SAxel Dörfler 10941bb87bd0SAxel Dörfler case kMsgTimeIntervalUpdated: 10951bb87bd0SAxel Dörfler bigtime_t interval; 10961bb87bd0SAxel Dörfler if (message->FindInt64("interval", &interval) != B_OK) 10971bb87bd0SAxel Dörfler break; 10981bb87bd0SAxel Dörfler 10991bb87bd0SAxel Dörfler if (interval < 10000) 11001bb87bd0SAxel Dörfler interval = 10000; 11011bb87bd0SAxel Dörfler 11021bb87bd0SAxel Dörfler atomic_set64(&fRefreshInterval, interval); 11031bb87bd0SAxel Dörfler break; 11041bb87bd0SAxel Dörfler 110518d3e65eSAxel Dörfler case kMsgToggleDataSource: 110618d3e65eSAxel Dörfler { 110718d3e65eSAxel Dörfler int32 index; 110818d3e65eSAxel Dörfler if (message->FindInt32("index", &index) != B_OK) 110918d3e65eSAxel Dörfler break; 111018d3e65eSAxel Dörfler 111118d3e65eSAxel Dörfler const DataSource* baseSource = DataSource::SourceAt(index); 111218d3e65eSAxel Dörfler if (baseSource == NULL) 111318d3e65eSAxel Dörfler break; 111418d3e65eSAxel Dörfler 11153a4a2141SAxel Dörfler DataSource* source = FindDataSource(baseSource); 111618d3e65eSAxel Dörfler if (source == NULL) 11173a4a2141SAxel Dörfler AddDataSource(baseSource); 111818d3e65eSAxel Dörfler else 111918d3e65eSAxel Dörfler RemoveDataSource(source); 112018d3e65eSAxel Dörfler 112118d3e65eSAxel Dörfler Invalidate(); 112218d3e65eSAxel Dörfler break; 112318d3e65eSAxel Dörfler } 112418d3e65eSAxel Dörfler 11253a4a2141SAxel Dörfler case kMsgToggleLegend: 11263a4a2141SAxel Dörfler fShowLegend = !fShowLegend; 11273a4a2141SAxel Dörfler Invalidate(); 11283a4a2141SAxel Dörfler break; 11293a4a2141SAxel Dörfler 113018d3e65eSAxel Dörfler case B_MOUSE_WHEEL_CHANGED: 113118d3e65eSAxel Dörfler { 113218d3e65eSAxel Dörfler float deltaY = 0.0f; 113318d3e65eSAxel Dörfler if (message->FindFloat("be:wheel_delta_y", &deltaY) != B_OK 113418d3e65eSAxel Dörfler || deltaY == 0.0f) 113518d3e65eSAxel Dörfler break; 113618d3e65eSAxel Dörfler 11371bb87bd0SAxel Dörfler int32 resolution = fDrawResolution; 113818d3e65eSAxel Dörfler if (deltaY > 0) 11391bb87bd0SAxel Dörfler resolution *= 2; 114018d3e65eSAxel Dörfler else 11411bb87bd0SAxel Dörfler resolution /= 2; 114218d3e65eSAxel Dörfler 11431bb87bd0SAxel Dörfler _UpdateResolution(resolution); 114418d3e65eSAxel Dörfler break; 114518d3e65eSAxel Dörfler } 114618d3e65eSAxel Dörfler 114718d3e65eSAxel Dörfler default: 114818d3e65eSAxel Dörfler BView::MessageReceived(message); 114918d3e65eSAxel Dörfler break; 115018d3e65eSAxel Dörfler } 115118d3e65eSAxel Dörfler } 115218d3e65eSAxel Dörfler 115318d3e65eSAxel Dörfler 1154065e8de0SAxel Dörfler void 1155065e8de0SAxel Dörfler ActivityView::_UpdateFrame() 1156065e8de0SAxel Dörfler { 1157dc1ffc79SFrançois Revol #ifdef __HAIKU__ 1158065e8de0SAxel Dörfler if (fLegendLayoutItem == NULL || fHistoryLayoutItem == NULL) 1159065e8de0SAxel Dörfler return; 1160065e8de0SAxel Dörfler 1161065e8de0SAxel Dörfler BRect historyFrame = fHistoryLayoutItem->Frame(); 1162065e8de0SAxel Dörfler BRect legendFrame = fLegendLayoutItem->Frame(); 1163dc1ffc79SFrançois Revol #else 1164dc1ffc79SFrançois Revol BRect historyFrame = Bounds(); 1165dc1ffc79SFrançois Revol BRect legendFrame = Bounds(); 1166dc1ffc79SFrançois Revol historyFrame.bottom -= 2 * Bounds().Height() / 3; 1167dc1ffc79SFrançois Revol legendFrame.top += Bounds().Height() / 3; 1168dc1ffc79SFrançois Revol #endif 1169065e8de0SAxel Dörfler MoveTo(historyFrame.left, historyFrame.top); 1170065e8de0SAxel Dörfler ResizeTo(legendFrame.left + legendFrame.Width() - historyFrame.left, 1171065e8de0SAxel Dörfler legendFrame.top + legendFrame.Height() - historyFrame.top); 1172065e8de0SAxel Dörfler } 1173065e8de0SAxel Dörfler 1174065e8de0SAxel Dörfler 11753a4a2141SAxel Dörfler BRect 11763a4a2141SAxel Dörfler ActivityView::_HistoryFrame() const 11773a4a2141SAxel Dörfler { 11783a4a2141SAxel Dörfler if (!fShowLegend) 11793a4a2141SAxel Dörfler return Bounds(); 11803a4a2141SAxel Dörfler 11813a4a2141SAxel Dörfler BRect frame = Bounds(); 11823a4a2141SAxel Dörfler BRect legendFrame = _LegendFrame(); 11833a4a2141SAxel Dörfler 11843a4a2141SAxel Dörfler frame.bottom = legendFrame.top - 1; 11853a4a2141SAxel Dörfler 11863a4a2141SAxel Dörfler return frame; 11873a4a2141SAxel Dörfler } 11883a4a2141SAxel Dörfler 11893a4a2141SAxel Dörfler 1190065e8de0SAxel Dörfler float 1191065e8de0SAxel Dörfler ActivityView::_LegendHeight() const 11923a4a2141SAxel Dörfler { 11933a4a2141SAxel Dörfler font_height fontHeight; 11943a4a2141SAxel Dörfler GetFontHeight(&fontHeight); 11953a4a2141SAxel Dörfler 1196d4216445SAxel Dörfler BAutolock _(fSourcesLock); 1197d4216445SAxel Dörfler 11983a4a2141SAxel Dörfler int32 rows = (fSources.CountItems() + 1) / 2; 1199065e8de0SAxel Dörfler return rows * (4 + ceilf(fontHeight.ascent) 12003a4a2141SAxel Dörfler + ceilf(fontHeight.descent) + ceilf(fontHeight.leading)); 1201065e8de0SAxel Dörfler } 1202065e8de0SAxel Dörfler 1203065e8de0SAxel Dörfler 1204065e8de0SAxel Dörfler BRect 1205065e8de0SAxel Dörfler ActivityView::_LegendFrame() const 1206065e8de0SAxel Dörfler { 1207065e8de0SAxel Dörfler float height; 1208dc1ffc79SFrançois Revol #ifdef __HAIKU__ 1209065e8de0SAxel Dörfler if (fLegendLayoutItem != NULL) 1210065e8de0SAxel Dörfler height = fLegendLayoutItem->Frame().Height(); 1211065e8de0SAxel Dörfler else 1212dc1ffc79SFrançois Revol #endif 1213065e8de0SAxel Dörfler height = _LegendHeight(); 1214065e8de0SAxel Dörfler 1215065e8de0SAxel Dörfler BRect frame = Bounds(); 1216065e8de0SAxel Dörfler frame.top = frame.bottom - height; 12173a4a2141SAxel Dörfler 12183a4a2141SAxel Dörfler return frame; 12193a4a2141SAxel Dörfler } 12203a4a2141SAxel Dörfler 12213a4a2141SAxel Dörfler 12223a4a2141SAxel Dörfler BRect 12233a4a2141SAxel Dörfler ActivityView::_LegendFrameAt(BRect frame, int32 index) const 12243a4a2141SAxel Dörfler { 12253a4a2141SAxel Dörfler int32 column = index & 1; 12263a4a2141SAxel Dörfler int32 row = index / 2; 12273a4a2141SAxel Dörfler if (column == 0) 12283a4a2141SAxel Dörfler frame.right = frame.left + floorf(frame.Width() / 2) - 5; 12293a4a2141SAxel Dörfler else 12303a4a2141SAxel Dörfler frame.left = frame.right - floorf(frame.Width() / 2) + 5; 12313a4a2141SAxel Dörfler 1232d4216445SAxel Dörfler BAutolock _(fSourcesLock); 1233d4216445SAxel Dörfler 12343a4a2141SAxel Dörfler int32 rows = (fSources.CountItems() + 1) / 2; 12353a4a2141SAxel Dörfler float height = floorf((frame.Height() - 5) / rows); 12363a4a2141SAxel Dörfler 12373a4a2141SAxel Dörfler frame.top = frame.top + 5 + row * height; 12383a4a2141SAxel Dörfler frame.bottom = frame.top + height - 1; 12393a4a2141SAxel Dörfler 12403a4a2141SAxel Dörfler return frame; 12413a4a2141SAxel Dörfler } 12423a4a2141SAxel Dörfler 12433a4a2141SAxel Dörfler 12441201d52eSAxel Dörfler BRect 12451201d52eSAxel Dörfler ActivityView::_LegendColorFrameAt(BRect frame, int32 index) const 12461201d52eSAxel Dörfler { 12471201d52eSAxel Dörfler frame = _LegendFrameAt(frame, index); 12481201d52eSAxel Dörfler frame.InsetBy(1, 1); 12491201d52eSAxel Dörfler frame.right = frame.left + frame.Height(); 12501201d52eSAxel Dörfler 12511201d52eSAxel Dörfler return frame; 12521201d52eSAxel Dörfler } 12531201d52eSAxel Dörfler 12541201d52eSAxel Dörfler 125518d3e65eSAxel Dörfler float 125618d3e65eSAxel Dörfler ActivityView::_PositionForValue(DataSource* source, DataHistory* values, 125718d3e65eSAxel Dörfler int64 value) 125818d3e65eSAxel Dörfler { 125918d3e65eSAxel Dörfler int64 min = source->Minimum(); 126018d3e65eSAxel Dörfler int64 max = source->Maximum(); 126118d3e65eSAxel Dörfler if (source->AdaptiveScale()) { 126218d3e65eSAxel Dörfler int64 adaptiveMax = int64(values->MaximumValue() * 1.2); 126318d3e65eSAxel Dörfler if (adaptiveMax < max) 126418d3e65eSAxel Dörfler max = adaptiveMax; 126518d3e65eSAxel Dörfler } 126618d3e65eSAxel Dörfler 126718d3e65eSAxel Dörfler if (value > max) 126818d3e65eSAxel Dörfler value = max; 126918d3e65eSAxel Dörfler if (value < min) 127018d3e65eSAxel Dörfler value = min; 127118d3e65eSAxel Dörfler 12723a4a2141SAxel Dörfler float height = _HistoryFrame().Height(); 127318d3e65eSAxel Dörfler return height - (value - min) * height / (max - min); 127418d3e65eSAxel Dörfler } 127518d3e65eSAxel Dörfler 127618d3e65eSAxel Dörfler 127718d3e65eSAxel Dörfler void 12783a4a2141SAxel Dörfler ActivityView::_DrawHistory() 127918d3e65eSAxel Dörfler { 12803a4a2141SAxel Dörfler _UpdateOffscreenBitmap(); 12813a4a2141SAxel Dörfler 12823a4a2141SAxel Dörfler BView* view = this; 12833a4a2141SAxel Dörfler if (fOffscreen != NULL) { 12843a4a2141SAxel Dörfler fOffscreen->Lock(); 12859c89c450SAxel Dörfler view = _OffscreenView(); 12863a4a2141SAxel Dörfler } 12873a4a2141SAxel Dörfler 12883a4a2141SAxel Dörfler BRect frame = _HistoryFrame(); 12891201d52eSAxel Dörfler view->SetLowColor(fHistoryBackgroundColor); 12903a4a2141SAxel Dörfler view->FillRect(frame, B_SOLID_LOW); 12913a4a2141SAxel Dörfler 129218d3e65eSAxel Dörfler uint32 step = 2; 129318d3e65eSAxel Dörfler uint32 resolution = fDrawResolution; 129418d3e65eSAxel Dörfler if (fDrawResolution > 1) { 129518d3e65eSAxel Dörfler step = 1; 129618d3e65eSAxel Dörfler resolution--; 129718d3e65eSAxel Dörfler } 129818d3e65eSAxel Dörfler 12993a4a2141SAxel Dörfler uint32 width = frame.IntegerWidth() - 10; 130018d3e65eSAxel Dörfler uint32 steps = width / step; 13011bb87bd0SAxel Dörfler bigtime_t timeStep = RefreshInterval() * resolution; 130218d3e65eSAxel Dörfler bigtime_t now = system_time(); 130318d3e65eSAxel Dörfler 13041201d52eSAxel Dörfler // Draw scale 13051201d52eSAxel Dörfler // TODO: add second markers? 13061201d52eSAxel Dörfler 13073a4a2141SAxel Dörfler view->SetPenSize(1); 13083a4a2141SAxel Dörfler 13091201d52eSAxel Dörfler rgb_color scaleColor = view->LowColor(); 13101201d52eSAxel Dörfler uint32 average = (scaleColor.red + scaleColor.green + scaleColor.blue) / 3; 13111201d52eSAxel Dörfler if (average < 96) 13121201d52eSAxel Dörfler scaleColor = tint_color(scaleColor, B_LIGHTEN_2_TINT); 13131201d52eSAxel Dörfler else 13141201d52eSAxel Dörfler scaleColor = tint_color(scaleColor, B_DARKEN_2_TINT); 13151201d52eSAxel Dörfler 13161201d52eSAxel Dörfler view->SetHighColor(scaleColor); 13173a4a2141SAxel Dörfler view->StrokeRect(frame); 13183a4a2141SAxel Dörfler view->StrokeLine(BPoint(frame.left, frame.top + frame.Height() / 2), 13193a4a2141SAxel Dörfler BPoint(frame.right, frame.top + frame.Height() / 2)); 13203a4a2141SAxel Dörfler 13211201d52eSAxel Dörfler // Draw values 13221201d52eSAxel Dörfler 13231bb87bd0SAxel Dörfler view->SetPenSize(1.5); 1324d4216445SAxel Dörfler BAutolock _(fSourcesLock); 132518d3e65eSAxel Dörfler 132618d3e65eSAxel Dörfler for (uint32 i = fSources.CountItems(); i-- > 0;) { 1327*8e26f387SAxel Dörfler ViewHistory* viewValues = fViewValues.ItemAt(i); 132818d3e65eSAxel Dörfler DataSource* source = fSources.ItemAt(i); 132918d3e65eSAxel Dörfler DataHistory* values = fValues.ItemAt(i); 133018d3e65eSAxel Dörfler 1331*8e26f387SAxel Dörfler viewValues->Update(values, steps, fDrawResolution, now, timeStep, 1332*8e26f387SAxel Dörfler RefreshInterval()); 1333*8e26f387SAxel Dörfler 1334*8e26f387SAxel Dörfler uint32 x = viewValues->Start() * step; 1335*8e26f387SAxel Dörfler BShape shape; 1336*8e26f387SAxel Dörfler bool first = true; 1337*8e26f387SAxel Dörfler 1338*8e26f387SAxel Dörfler for (uint32 i = viewValues->Start(); i < steps; x += step, i++) { 1339*8e26f387SAxel Dörfler float y = _PositionForValue(source, values, 1340*8e26f387SAxel Dörfler viewValues->ValueAt(i)); 1341*8e26f387SAxel Dörfler 1342*8e26f387SAxel Dörfler if (first) { 1343*8e26f387SAxel Dörfler shape.MoveTo(BPoint(x, y)); 1344*8e26f387SAxel Dörfler first = false; 1345*8e26f387SAxel Dörfler } else 1346*8e26f387SAxel Dörfler shape.LineTo(BPoint(x, y)); 1347*8e26f387SAxel Dörfler } 1348*8e26f387SAxel Dörfler 13493a4a2141SAxel Dörfler view->SetHighColor(source->Color()); 1350*8e26f387SAxel Dörfler view->SetLineMode(B_BUTT_CAP, B_ROUND_JOIN); 1351*8e26f387SAxel Dörfler view->MovePenTo(B_ORIGIN); 1352*8e26f387SAxel Dörfler view->StrokeShape(&shape); 135318d3e65eSAxel Dörfler } 135418d3e65eSAxel Dörfler 135518d3e65eSAxel Dörfler // TODO: add marks when an app started or quit 13563a4a2141SAxel Dörfler view->Sync(); 13573a4a2141SAxel Dörfler if (fOffscreen != NULL) { 13583a4a2141SAxel Dörfler fOffscreen->Unlock(); 13594e78d3bcSStephan Aßmus DrawBitmap(fOffscreen, B_ORIGIN); 13603a4a2141SAxel Dörfler } 13613a4a2141SAxel Dörfler } 13623a4a2141SAxel Dörfler 13633a4a2141SAxel Dörfler 13643a4a2141SAxel Dörfler void 13651bb87bd0SAxel Dörfler ActivityView::_UpdateResolution(int32 resolution, bool broadcast) 13661bb87bd0SAxel Dörfler { 13671bb87bd0SAxel Dörfler if (resolution < 1) 13681bb87bd0SAxel Dörfler resolution = 1; 13691bb87bd0SAxel Dörfler if (resolution > 128) 13701bb87bd0SAxel Dörfler resolution = 128; 13711bb87bd0SAxel Dörfler 13721bb87bd0SAxel Dörfler if (resolution == fDrawResolution) 13731bb87bd0SAxel Dörfler return; 13741bb87bd0SAxel Dörfler 13751bb87bd0SAxel Dörfler ActivityWindow* window = dynamic_cast<ActivityWindow*>(Window()); 13761bb87bd0SAxel Dörfler if (broadcast && window != NULL) { 13771bb87bd0SAxel Dörfler BMessage update(kMsgUpdateResolution); 13781bb87bd0SAxel Dörfler update.AddInt32("resolution", resolution); 13791bb87bd0SAxel Dörfler window->BroadcastToActivityViews(&update, this); 13801bb87bd0SAxel Dörfler } 13811bb87bd0SAxel Dörfler 13821bb87bd0SAxel Dörfler fDrawResolution = resolution; 13831bb87bd0SAxel Dörfler Invalidate(); 13841bb87bd0SAxel Dörfler } 13851bb87bd0SAxel Dörfler 13861bb87bd0SAxel Dörfler 13871bb87bd0SAxel Dörfler void 13883a4a2141SAxel Dörfler ActivityView::Draw(BRect /*updateRect*/) 13893a4a2141SAxel Dörfler { 13903a4a2141SAxel Dörfler _DrawHistory(); 13913a4a2141SAxel Dörfler 13923a4a2141SAxel Dörfler if (!fShowLegend) 13933a4a2141SAxel Dörfler return; 13943a4a2141SAxel Dörfler 13953a4a2141SAxel Dörfler // draw legend 13963a4a2141SAxel Dörfler 1397d4216445SAxel Dörfler BAutolock _(fSourcesLock); 13983a4a2141SAxel Dörfler BRect legendFrame = _LegendFrame(); 13999c89c450SAxel Dörfler 14009c89c450SAxel Dörfler SetLowColor(fLegendBackgroundColor); 14013a4a2141SAxel Dörfler FillRect(legendFrame, B_SOLID_LOW); 14023a4a2141SAxel Dörfler 14033a4a2141SAxel Dörfler font_height fontHeight; 14043a4a2141SAxel Dörfler GetFontHeight(&fontHeight); 14053a4a2141SAxel Dörfler 14063a4a2141SAxel Dörfler for (int32 i = 0; i < fSources.CountItems(); i++) { 14073a4a2141SAxel Dörfler DataSource* source = fSources.ItemAt(i); 14083a4a2141SAxel Dörfler DataHistory* values = fValues.ItemAt(i); 14093a4a2141SAxel Dörfler BRect frame = _LegendFrameAt(legendFrame, i); 14103a4a2141SAxel Dörfler 14113a4a2141SAxel Dörfler // draw color box 14121201d52eSAxel Dörfler BRect colorBox = _LegendColorFrameAt(legendFrame, i); 14133a4a2141SAxel Dörfler SetHighColor(tint_color(source->Color(), B_DARKEN_1_TINT)); 14143a4a2141SAxel Dörfler StrokeRect(colorBox); 14153a4a2141SAxel Dörfler SetHighColor(source->Color()); 14163a4a2141SAxel Dörfler colorBox.InsetBy(1, 1); 14173a4a2141SAxel Dörfler FillRect(colorBox); 14183a4a2141SAxel Dörfler 14193a4a2141SAxel Dörfler // show current value and label 14203a4a2141SAxel Dörfler float y = frame.top + ceilf(fontHeight.ascent); 14213a4a2141SAxel Dörfler int64 value = values->ValueAt(values->End()); 14223a4a2141SAxel Dörfler BString text; 14233a4a2141SAxel Dörfler source->Print(text, value); 14243a4a2141SAxel Dörfler float width = StringWidth(text.String()); 14253a4a2141SAxel Dörfler 14263a4a2141SAxel Dörfler BString label = source->Label(); 14273a4a2141SAxel Dörfler TruncateString(&label, B_TRUNCATE_MIDDLE, 14283a4a2141SAxel Dörfler frame.right - colorBox.right - 12 - width); 14293a4a2141SAxel Dörfler 14303a4a2141SAxel Dörfler SetHighColor(ui_color(B_CONTROL_TEXT_COLOR)); 14313a4a2141SAxel Dörfler DrawString(label.String(), BPoint(6 + colorBox.right, y)); 14323a4a2141SAxel Dörfler DrawString(text.String(), BPoint(frame.right - width, y)); 14333a4a2141SAxel Dörfler } 143418d3e65eSAxel Dörfler } 143518d3e65eSAxel Dörfler 143618d3e65eSAxel Dörfler 143718d3e65eSAxel Dörfler void 143818d3e65eSAxel Dörfler ActivityView::_Refresh() 143918d3e65eSAxel Dörfler { 14401bb87bd0SAxel Dörfler bigtime_t lastTimeout = system_time() - RefreshInterval(); 14414ce1e1d2SAxel Dörfler BMessenger target(this); 144218d3e65eSAxel Dörfler 1443d4216445SAxel Dörfler while (true) { 1444d4216445SAxel Dörfler status_t status = acquire_sem_etc(fRefreshSem, 1, B_ABSOLUTE_TIMEOUT, 14451bb87bd0SAxel Dörfler lastTimeout + RefreshInterval()); 1446d4216445SAxel Dörfler if (status == B_OK || status == B_BAD_SEM_ID) 1447d4216445SAxel Dörfler break; 1448d4216445SAxel Dörfler if (status == B_INTERRUPTED) 1449d4216445SAxel Dörfler continue; 1450d4216445SAxel Dörfler 1451d4216445SAxel Dörfler SystemInfo info(fSystemInfoHandler); 14521bb87bd0SAxel Dörfler lastTimeout += RefreshInterval(); 1453d4216445SAxel Dörfler 1454d4216445SAxel Dörfler fSourcesLock.Lock(); 145518d3e65eSAxel Dörfler 145618d3e65eSAxel Dörfler for (uint32 i = fSources.CountItems(); i-- > 0;) { 145718d3e65eSAxel Dörfler DataSource* source = fSources.ItemAt(i); 145818d3e65eSAxel Dörfler DataHistory* values = fValues.ItemAt(i); 145918d3e65eSAxel Dörfler 146018d3e65eSAxel Dörfler int64 value = source->NextValue(info); 146118d3e65eSAxel Dörfler values->AddValue(info.Time(), value); 146218d3e65eSAxel Dörfler } 146318d3e65eSAxel Dörfler 1464d4216445SAxel Dörfler fSourcesLock.Unlock(); 1465d4216445SAxel Dörfler 14664ce1e1d2SAxel Dörfler target.SendMessage(B_INVALIDATE); 146718d3e65eSAxel Dörfler } 1468d4216445SAxel Dörfler } 146918d3e65eSAxel Dörfler 1470d4216445SAxel Dörfler 1471d4216445SAxel Dörfler /*static*/ status_t 1472d4216445SAxel Dörfler ActivityView::_RefreshThread(void* self) 1473d4216445SAxel Dörfler { 1474d4216445SAxel Dörfler ((ActivityView*)self)->_Refresh(); 1475d4216445SAxel Dörfler return B_OK; 1476d4216445SAxel Dörfler } 1477