xref: /haiku/src/apps/networkstatus/RadioView.cpp (revision bab64f65bb775dc23060e276f1f1c4498ab7af6c)
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 
RadioView(BRect frame,const char * name,int32 resizingMode)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(DefaultMax())
29 {
30 }
31 
32 
~RadioView()33 RadioView::~RadioView()
34 {
35 }
36 
37 
38 void
SetPercent(int32 percent)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
SetMax(int32 max)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
StartPulsing()70 RadioView::StartPulsing()
71 {
72 	fPhase = 0;
73 	_RestartPulsing();
74 }
75 
76 
77 void
StopPulsing()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 /*static*/ void
Draw(BView * view,BRect rect,int32 percent,int32 maxCount)91 RadioView::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
DefaultMax()109 RadioView::DefaultMax()
110 {
111 	return 7;
112 }
113 
114 
115 void
AttachedToWindow()116 RadioView::AttachedToWindow()
117 {
118 	if (Parent() != NULL)
119 		SetViewColor(Parent()->ViewColor());
120 	else
121 		SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
122 }
123 
124 
125 void
DetachedFromWindow()126 RadioView::DetachedFromWindow()
127 {
128 	StopPulsing();
129 }
130 
131 
132 void
MessageReceived(BMessage * message)133 RadioView::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 
148 void
Draw(BRect updateRect)149 RadioView::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 
168 void
FrameResized(float,float)169 RadioView::FrameResized(float /*width*/, float /*height*/)
170 {
171 	if (IsPulsing())
172 		_RestartPulsing();
173 }
174 
175 
176 void
_RestartPulsing()177 RadioView::_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
_Compute(const BRect & bounds,BPoint & center,int32 & count,int32 max,float & step)194 RadioView::_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
_DrawBow(BView * view,int32 index,const BPoint & center,int32 count,float step)211 RadioView::_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
_SetColor(BView * view,int32 percent,int32 phase,int32 index,int32 count)227 RadioView::_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
_IsDisabled(int32 percent,int32 index,int32 count)244 RadioView::_IsDisabled(int32 percent, int32 index, int32 count)
245 {
246 	return percent < 100 * index / count;
247 }
248