1/* 2 * Copyright 2010, Axel D��rfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7#include "RadioView.h" 8 9#include <stdio.h> 10 11#include <MessageRunner.h> 12 13 14const uint32 kMsgPulse = 'puls'; 15 16const bigtime_t kMinPulseInterval = 100000; 17const bigtime_t kMaxPulseInterval = 300000; 18const float kMinStep = 3.f; 19 20 21RadioView::RadioView(BRect frame, const char* name, int32 resizingMode) 22 : 23 BView(frame, name, resizingMode, 24 B_FULL_UPDATE_ON_RESIZE | B_WILL_DRAW | B_FRAME_EVENTS), 25 fPercent(0), 26 fPulse(NULL), 27 fPhase(0), 28 fMax(DefaultMax()) 29{ 30} 31 32 33RadioView::~RadioView() 34{ 35} 36 37 38void 39RadioView::SetPercent(int32 percent) 40{ 41 if (percent < 0) 42 percent = 0; 43 if (percent > 100) 44 percent = 100; 45 46 if (percent == fPercent) 47 return; 48 49 fPercent = percent; 50 Invalidate(); 51} 52 53 54void 55RadioView::SetMax(int32 max) 56{ 57 if (max < 0) 58 max = 0; 59 if (max > 100) 60 max = 100; 61 if (max == fMax) 62 return; 63 64 fMax = max; 65 Invalidate(); 66} 67 68 69void 70RadioView::StartPulsing() 71{ 72 fPhase = 0; 73 _RestartPulsing(); 74} 75 76 77void 78RadioView::StopPulsing() 79{ 80 if (!IsPulsing()) 81 return; 82 83 delete fPulse; 84 fPulse = NULL; 85 fPhase = 0; 86 Invalidate(); 87} 88 89 90/*static*/ void 91RadioView::Draw(BView* view, BRect rect, int32 percent, int32 maxCount) 92{ 93 view->PushState(); 94 95 BPoint center; 96 int32 count; 97 float step; 98 _Compute(rect, center, count, maxCount, step); 99 100 for (int32 i = 0; i < count; i++) { 101 _SetColor(view, percent, 0, i, count); 102 _DrawBow(view, i, center, count, step); 103 } 104 view->PopState(); 105} 106 107 108/*static*/ int32 109RadioView::DefaultMax() 110{ 111 return 7; 112} 113 114 115void 116RadioView::AttachedToWindow() 117{ 118 if (Parent() != NULL) 119 SetViewColor(Parent()->ViewColor()); 120 else 121 SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 122} 123 124 125void 126RadioView::DetachedFromWindow() 127{ 128 StopPulsing(); 129} 130 131 132void 133RadioView::MessageReceived(BMessage* message) 134{ 135 switch (message->what) { 136 case kMsgPulse: 137 fPhase++; 138 Invalidate(); 139 break; 140 141 default: 142 BView::MessageReceived(message); 143 break; 144 } 145} 146 147 148void 149RadioView::Draw(BRect updateRect) 150{ 151 SetLowColor(ViewColor()); 152 153 BPoint center; 154 int32 count; 155 float step; 156 _Compute(Bounds(), center, count, fMax, step); 157 158 for (int32 i = 0; i < count; i++) { 159 _SetColor(this, fPercent, fPhase, i, count); 160 if (step == kMinStep && _IsDisabled(fPercent, i, count)) 161 continue; 162 163 _DrawBow(this, i, center, count, step); 164 } 165} 166 167 168void 169RadioView::FrameResized(float /*width*/, float /*height*/) 170{ 171 if (IsPulsing()) 172 _RestartPulsing(); 173} 174 175 176void 177RadioView::_RestartPulsing() 178{ 179 delete fPulse; 180 181 // The pulse speed depends on the size of the view 182 BPoint center; 183 int32 count; 184 float step; 185 _Compute(Bounds(), center, count, fMax, step); 186 187 BMessage message(kMsgPulse); 188 fPulse = new BMessageRunner(this, &message, (bigtime_t)(kMinPulseInterval 189 + (kMaxPulseInterval - kMinPulseInterval) / step), -1); 190} 191 192 193/*static*/ void 194RadioView::_Compute(const BRect& bounds, BPoint& center, int32& count, 195 int32 max, float& step) 196{ 197 center.Set(roundf(bounds.Width() / 2), bounds.bottom); 198 float size = min_c(center.x * 3 / 2, center.y); 199 step = floorf(size / max); 200 if (step < kMinStep) { 201 count = (int32)(size / kMinStep); 202 step = kMinStep; 203 } else 204 count = max; 205 206 center.x += bounds.left; 207} 208 209 210/*static*/ void 211RadioView::_DrawBow(BView* view, int32 index, const BPoint& center, 212 int32 count, float step) 213{ 214 float radius = step * index + 1; 215 216 if (step < 4) 217 view->SetPenSize(step / 2); 218 else 219 view->SetPenSize(step * 2 / 3); 220 221 view->SetLineMode(B_ROUND_CAP, B_ROUND_JOIN); 222 view->StrokeArc(center, radius, radius, 50, 80); 223} 224 225 226/*static*/ void 227RadioView::_SetColor(BView* view, int32 percent, int32 phase, int32 index, 228 int32 count) 229{ 230 if (_IsDisabled(percent, index, count)) { 231 // disabled 232 view->SetHighColor(tint_color(view->LowColor(), B_DARKEN_1_TINT)); 233 } else if (phase == 0 || phase % count != index) { 234 // enabled 235 view->SetHighColor(tint_color(view->LowColor(), B_DARKEN_3_TINT)); 236 } else { 237 // pulsing 238 view->SetHighColor(tint_color(view->LowColor(), B_DARKEN_2_TINT)); 239 } 240} 241 242 243/*static*/ bool 244RadioView::_IsDisabled(int32 percent, int32 index, int32 count) 245{ 246 return percent < 100 * index / count; 247} 248