xref: /haiku/src/apps/mediaplayer/interface/VolumeSlider.cpp (revision 220d04022750f40f8bac8f01fa551211e28d04f2)
1 /*
2  * Copyright 2010, Stephan Aßmus <superstippi@gmx.de>.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "VolumeSlider.h"
8 
9 #include <GradientLinear.h>
10 
11 #include <stdio.h>
12 #include <string.h>
13 
14 
15 #define KNOB_EMBEDDED 0
16 #define ROUND_KNOB 0
17 
18 static const rgb_color kGreen = (rgb_color){ 116, 224, 0, 255 };
19 
20 
21 // constructor
22 VolumeSlider::VolumeSlider(const char* name, int32 minValue, int32 maxValue,
23 		int32 snapValue, BMessage* message)
24 	:
25 	BSlider(name, NULL, NULL, minValue, maxValue, B_HORIZONTAL,
26 		B_BLOCK_THUMB),
27 	fMuted(false),
28 	fSnapValue(snapValue),
29 	fSnapping(false)
30 {
31 	SetModificationMessage(message);
32 	UseFillColor(true, &kGreen);
33 	SetBarThickness(PreferredBarThickness());
34 }
35 
36 
37 VolumeSlider::~VolumeSlider()
38 {
39 }
40 
41 
42 void
43 VolumeSlider::MouseMoved(BPoint where, uint32 transit,
44 	const BMessage* dragMessage)
45 {
46 	if (!IsTracking()) {
47 		BSlider::MouseMoved(where, transit, dragMessage);
48 		return;
49 	}
50 
51 	float cursorPosition = Orientation() == B_HORIZONTAL ? where.x : where.y;
52 
53 	if (fSnapping
54 		&& cursorPosition >= fMinSnap && cursorPosition <= fMaxSnap) {
55 		// Don't move the slider, keep the current value for a few
56 		// more pixels
57 		return;
58 	}
59 
60 	fSnapping = false;
61 
62 	int32 oldValue = Value();
63 	int32 newValue = ValueForPoint(where);
64 	if (oldValue == newValue) {
65 		BSlider::MouseMoved(where, transit, dragMessage);
66 		return;
67 	}
68 
69 	// Check if there is a 0 dB transition at all
70 	if ((oldValue < fSnapValue && newValue >= fSnapValue)
71 		|| (oldValue > fSnapValue && newValue <= fSnapValue)) {
72 		SetValue(fSnapValue);
73 		if (ModificationMessage() != NULL)
74 			Messenger().SendMessage(ModificationMessage());
75 
76 		float snapPoint = _PointForValue(fSnapValue);
77 		const float kMaxSnapOffset = 6;
78 		if (oldValue > newValue) {
79 			// movement from right to left
80 			fMinSnap = snapPoint - kMaxSnapOffset;
81 			fMaxSnap = snapPoint + 1;
82 		} else {
83 			// movement from left to right
84 			fMinSnap = snapPoint - 1;
85 			fMaxSnap = snapPoint + kMaxSnapOffset;
86 		}
87 
88 		fSnapping = true;
89 		return;
90 	}
91 
92 	BSlider::MouseMoved(where, transit, dragMessage);
93 }
94 
95 
96 BRect
97 VolumeSlider::ThumbFrame() const
98 {
99 #if !ROUND_KNOB
100 	BRect rect = BSlider::ThumbFrame();
101 	rect.InsetBy(2, 2);
102 	rect.bottom += 1;
103 #else
104 	BRect rect(BarFrame());
105 #	if KNOB_EMBEDDED
106 	// Knob embedded in bar frame
107 	rect.InsetBy(0, 1);
108 #	else
109 	// Knob extends outside the bar frame
110 	rect.InsetBy(0, -1);
111 #	endif
112 	rect.InsetBy(rect.Height() / 2, 0);
113 	rect.left = rect.left + rect.Width() * Position() - rect.Height() / 2;
114 	rect.right = rect.left + rect.Height();
115 #endif
116 
117 	return rect;
118 }
119 
120 
121 void
122 VolumeSlider::DrawThumb()
123 {
124 #if ROUND_KNOB
125 	// Draw a round thumb
126 	BRect rect(ThumbFrame());
127 
128 	rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
129 	rgb_color frameLightColor;
130 	rgb_color frameShadowColor;
131 	rgb_color shadowColor = (rgb_color){ 0, 0, 0, 60 };
132 
133 	float topTint = 0.49;
134 	float middleTint1 = 0.62;
135 	float middleTint2 = 0.76;
136 	float bottomTint = 0.90;
137 
138 	if (!IsEnabled()) {
139 		topTint = (topTint + B_NO_TINT) / 2;
140 		middleTint1 = (middleTint1 + B_NO_TINT) / 2;
141 		middleTint2 = (middleTint2 + B_NO_TINT) / 2;
142 		bottomTint = (bottomTint + B_NO_TINT) / 2;
143 		shadowColor = (rgb_color){ 0, 0, 0, 30 };
144 	}
145 
146 	// Draw shadow
147 #if !KNOB_EMBEDDED
148 	rect.left++;
149 	rect.top++;
150 	SetDrawingMode(B_OP_ALPHA);
151 	SetHighColor(shadowColor);
152 	FillEllipse(rect);
153 
154 	// Draw thumb shape
155 	rect.OffsetBy(-1, -1);
156 #endif
157 
158 	if (IsFocus()) {
159 		// focused
160 		frameLightColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
161 		frameShadowColor = frameLightColor;
162 	} else {
163 		// figure out the tints to be used
164 		float frameLightTint;
165 		float frameShadowTint;
166 
167 		if (!IsEnabled()) {
168 			frameLightTint = 1.30;
169 			frameShadowTint = 1.35;
170 			shadowColor.alpha = 30;
171 		} else {
172 			frameLightTint = 1.6;
173 			frameShadowTint = 1.65;
174 		}
175 
176 		frameLightColor = tint_color(base, frameLightTint);
177 		frameShadowColor = tint_color(base, frameShadowTint);
178 	}
179 
180 	BGradientLinear frameGradient;
181 	frameGradient.AddColor(frameShadowColor, 0);
182 	frameGradient.AddColor(frameLightColor, 255);
183 	frameGradient.SetStart(rect.LeftTop());
184 	frameGradient.SetEnd(rect.RightBottom());
185 
186 	FillEllipse(rect, frameGradient);
187 	rect.InsetBy(1, 1);
188 
189 //	frameGradient.MakeEmpty();
190 //	frameGradient.AddColor(borderColor, 0);
191 //	frameGradient.AddColor(tint_color(borderColor, 0.8), 255);
192 //	view->FillEllipse(rect, frameGradient);
193 //	rect.InsetBy(1, 1);
194 
195 	BGradientLinear gradient;
196 	if (!IsEnabled()) {
197 		gradient.AddColor(tint_color(base, topTint), 0);
198 		gradient.AddColor(tint_color(base, bottomTint), 255);
199 	} else {
200 		gradient.AddColor(tint_color(base, topTint), 0);
201 		gradient.AddColor(tint_color(base, middleTint1), 132);
202 		gradient.AddColor(tint_color(base, middleTint2), 136);
203 		gradient.AddColor(tint_color(base, bottomTint), 255);
204 	}
205 	gradient.SetStart(rect.LeftTop());
206 	gradient.SetEnd(rect.LeftBottom());
207 	FillEllipse(rect, gradient);
208 #else
209 	BSlider::DrawThumb();
210 #endif
211 }
212 
213 
214 BSize
215 VolumeSlider::MinSize()
216 {
217 	BSize size = BSlider::MinSize();
218 	size.width *= 2;
219 	return size;
220 }
221 
222 
223 void
224 VolumeSlider::SetMuted(bool mute)
225 {
226 	if (mute == fMuted)
227 		return;
228 
229 	fMuted = mute;
230 
231 	rgb_color fillColor = kGreen;
232 	if (fMuted) {
233 		fillColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
234 			B_DARKEN_2_TINT);
235 	}
236 
237 	UseFillColor(true, &fillColor);
238 
239 	Invalidate();
240 }
241 
242 
243 float
244 VolumeSlider::PreferredBarThickness() const
245 {
246 #if KNOB_EMBEDDED
247 	return 10.0f;
248 #else
249 	return 8.0f;
250 #endif
251 }
252 
253 
254 float
255 VolumeSlider::_PointForValue(int32 value) const
256 {
257 	int32 min, max;
258 	GetLimits(&min, &max);
259 
260 	if (Orientation() == B_HORIZONTAL) {
261 		return ceilf(1.0f * (value - min) / (max - min)
262 			* (BarFrame().Width() - 2) + BarFrame().left + 1);
263 	}
264 
265 	return ceilf(BarFrame().top - 1.0f * (value - min) / (max - min)
266 		* BarFrame().Height());
267 }
268 
269 
270