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 14 const uint32 kMsgPulse = 'puls'; 15 16 const bigtime_t kMinPulseInterval = 100000; 17 const bigtime_t kMaxPulseInterval = 300000; 18 const float kMinStep = 3.f; 19 20 21 RadioView::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(7) 29 { 30 } 31 32 33 RadioView::~RadioView() 34 { 35 } 36 37 38 void 39 RadioView::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 54 void 55 RadioView::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 69 void 70 RadioView::StartPulsing() 71 { 72 fPhase = 0; 73 _RestartPulsing(); 74 } 75 76 77 void 78 RadioView::StopPulsing() 79 { 80 if (!IsPulsing()) 81 return; 82 83 delete fPulse; 84 fPulse = NULL; 85 fPhase = 0; 86 Invalidate(); 87 } 88 89 90 void 91 RadioView::AttachedToWindow() 92 { 93 if (Parent() != NULL) 94 SetViewColor(Parent()->ViewColor()); 95 else 96 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 97 } 98 99 100 void 101 RadioView::DetachedFromWindow() 102 { 103 StopPulsing(); 104 } 105 106 107 void 108 RadioView::MessageReceived(BMessage* message) 109 { 110 switch (message->what) { 111 case kMsgPulse: 112 fPhase++; 113 Invalidate(); 114 break; 115 116 default: 117 BView::MessageReceived(message); 118 break; 119 } 120 } 121 122 123 void 124 RadioView::Draw(BRect updateRect) 125 { 126 SetLowColor(ViewColor()); 127 128 BPoint center; 129 int32 count; 130 float step; 131 _Compute(Bounds(), center, count, step); 132 133 for (int32 i = 0; i < count; i++) { 134 _SetColor(i, count); 135 if (step == kMinStep && _IsDisabled(i, count)) 136 continue; 137 138 _DrawBow(i, center, count, step); 139 } 140 } 141 142 143 void 144 RadioView::FrameResized(float /*width*/, float /*height*/) 145 { 146 if (IsPulsing()) 147 _RestartPulsing(); 148 } 149 150 151 void 152 RadioView::_RestartPulsing() 153 { 154 delete fPulse; 155 156 // The pulse speed depends on the size of the view 157 BPoint center; 158 int32 count; 159 float step; 160 _Compute(Bounds(), center, count, step); 161 162 BMessage message(kMsgPulse); 163 fPulse = new BMessageRunner(this, &message, (bigtime_t)(kMinPulseInterval 164 + (kMaxPulseInterval - kMinPulseInterval) / step), -1); 165 } 166 167 168 void 169 RadioView::_Compute(const BRect& bounds, BPoint& center, int32& count, 170 float& step) const 171 { 172 center.Set(roundf(bounds.Width() / 2), bounds.bottom); 173 float size = min_c(center.x * 3 / 2, center.y); 174 step = floorf(size / fMax); 175 if (step < kMinStep) { 176 count = (int32)(size / kMinStep); 177 step = kMinStep; 178 } else 179 count = fMax; 180 } 181 182 183 void 184 RadioView::_DrawBow(int32 index, const BPoint& center, int32 count, float step) 185 { 186 float radius = step * index + 1; 187 188 if (step < 4) 189 SetPenSize(step / 2); 190 else 191 SetPenSize(step * 2 / 3); 192 193 SetLineMode(B_ROUND_CAP, B_ROUND_JOIN); 194 StrokeArc(center, radius, radius, 50, 80); 195 } 196 197 198 void 199 RadioView::_SetColor(int32 index, int32 count) 200 { 201 if (_IsDisabled(index, count)) { 202 // disabled 203 SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); 204 } else if (fPhase == 0 || fPhase % count != index) { 205 // enabled 206 SetHighColor(tint_color(ViewColor(), B_DARKEN_3_TINT)); 207 } else { 208 // pulsing 209 SetHighColor(tint_color(ViewColor(), B_DARKEN_2_TINT)); 210 } 211 } 212 213 214 bool 215 RadioView::_IsDisabled(int32 index, int32 count) const 216 { 217 return fPercent < 100 * index / count; 218 } 219