10fc56ed5SStephan Aßmus /*
2b000c602SStephan Aßmus * Copyright 2010, Stephan Aßmus <superstippi@gmx.de>.
30fc56ed5SStephan Aßmus * Distributed under the terms of the MIT License.
40fc56ed5SStephan Aßmus */
50fc56ed5SStephan Aßmus
60fc56ed5SStephan Aßmus
70fc56ed5SStephan Aßmus #include "VolumeSlider.h"
80fc56ed5SStephan Aßmus
9b000c602SStephan Aßmus #include <GradientLinear.h>
100fc56ed5SStephan Aßmus
110fc56ed5SStephan Aßmus #include <stdio.h>
120fc56ed5SStephan Aßmus #include <string.h>
130fc56ed5SStephan Aßmus
140fc56ed5SStephan Aßmus
15b000c602SStephan Aßmus #define KNOB_EMBEDDED 0
16*9291985bSStephan Aßmus #define ROUND_KNOB 0
170fc56ed5SStephan Aßmus
18b000c602SStephan Aßmus static const rgb_color kGreen = (rgb_color){ 116, 224, 0, 255 };
19b000c602SStephan Aßmus
200fc56ed5SStephan Aßmus
210fc56ed5SStephan Aßmus // constructor
VolumeSlider(const char * name,int32 minValue,int32 maxValue,int32 snapValue,BMessage * message)22b000c602SStephan Aßmus VolumeSlider::VolumeSlider(const char* name, int32 minValue, int32 maxValue,
23b000c602SStephan Aßmus int32 snapValue, BMessage* message)
24b000c602SStephan Aßmus :
25b000c602SStephan Aßmus BSlider(name, NULL, NULL, minValue, maxValue, B_HORIZONTAL,
26*9291985bSStephan Aßmus B_BLOCK_THUMB),
270fc56ed5SStephan Aßmus fMuted(false),
28b000c602SStephan Aßmus fSnapValue(snapValue),
29b000c602SStephan Aßmus fSnapping(false)
300fc56ed5SStephan Aßmus {
31b000c602SStephan Aßmus SetModificationMessage(message);
32b000c602SStephan Aßmus UseFillColor(true, &kGreen);
33341ea11eSStephan Aßmus SetBarThickness(PreferredBarThickness());
340fc56ed5SStephan Aßmus }
350fc56ed5SStephan Aßmus
36b000c602SStephan Aßmus
~VolumeSlider()370fc56ed5SStephan Aßmus VolumeSlider::~VolumeSlider()
380fc56ed5SStephan Aßmus {
390fc56ed5SStephan Aßmus }
400fc56ed5SStephan Aßmus
41b000c602SStephan Aßmus
420fc56ed5SStephan Aßmus void
MouseMoved(BPoint where,uint32 transit,const BMessage * dragMessage)43b000c602SStephan Aßmus VolumeSlider::MouseMoved(BPoint where, uint32 transit,
44b000c602SStephan Aßmus const BMessage* dragMessage)
450fc56ed5SStephan Aßmus {
46b000c602SStephan Aßmus if (!IsTracking()) {
47b000c602SStephan Aßmus BSlider::MouseMoved(where, transit, dragMessage);
480fc56ed5SStephan Aßmus return;
490fc56ed5SStephan Aßmus }
500fc56ed5SStephan Aßmus
51b000c602SStephan Aßmus float cursorPosition = Orientation() == B_HORIZONTAL ? where.x : where.y;
52b000c602SStephan Aßmus
53b000c602SStephan Aßmus if (fSnapping
54b000c602SStephan Aßmus && cursorPosition >= fMinSnap && cursorPosition <= fMaxSnap) {
55b000c602SStephan Aßmus // Don't move the slider, keep the current value for a few
56b000c602SStephan Aßmus // more pixels
57b000c602SStephan Aßmus return;
58b000c602SStephan Aßmus }
59b000c602SStephan Aßmus
60b000c602SStephan Aßmus fSnapping = false;
61b000c602SStephan Aßmus
62b000c602SStephan Aßmus int32 oldValue = Value();
63b000c602SStephan Aßmus int32 newValue = ValueForPoint(where);
64b000c602SStephan Aßmus if (oldValue == newValue) {
65b000c602SStephan Aßmus BSlider::MouseMoved(where, transit, dragMessage);
66b000c602SStephan Aßmus return;
67b000c602SStephan Aßmus }
68b000c602SStephan Aßmus
69b000c602SStephan Aßmus // Check if there is a 0 dB transition at all
70b000c602SStephan Aßmus if ((oldValue < fSnapValue && newValue >= fSnapValue)
71b000c602SStephan Aßmus || (oldValue > fSnapValue && newValue <= fSnapValue)) {
72b000c602SStephan Aßmus SetValue(fSnapValue);
73b000c602SStephan Aßmus if (ModificationMessage() != NULL)
74b000c602SStephan Aßmus Messenger().SendMessage(ModificationMessage());
75b000c602SStephan Aßmus
76b000c602SStephan Aßmus float snapPoint = _PointForValue(fSnapValue);
77b000c602SStephan Aßmus const float kMaxSnapOffset = 6;
78b000c602SStephan Aßmus if (oldValue > newValue) {
79b000c602SStephan Aßmus // movement from right to left
80b000c602SStephan Aßmus fMinSnap = snapPoint - kMaxSnapOffset;
81b000c602SStephan Aßmus fMaxSnap = snapPoint + 1;
82b000c602SStephan Aßmus } else {
83b000c602SStephan Aßmus // movement from left to right
84b000c602SStephan Aßmus fMinSnap = snapPoint - 1;
85b000c602SStephan Aßmus fMaxSnap = snapPoint + kMaxSnapOffset;
86b000c602SStephan Aßmus }
87b000c602SStephan Aßmus
88b000c602SStephan Aßmus fSnapping = true;
89b000c602SStephan Aßmus return;
90b000c602SStephan Aßmus }
91b000c602SStephan Aßmus
92b000c602SStephan Aßmus BSlider::MouseMoved(where, transit, dragMessage);
93b000c602SStephan Aßmus }
94b000c602SStephan Aßmus
95b000c602SStephan Aßmus
96b000c602SStephan Aßmus BRect
ThumbFrame() const97b000c602SStephan Aßmus VolumeSlider::ThumbFrame() const
98b000c602SStephan Aßmus {
99*9291985bSStephan Aßmus #if !ROUND_KNOB
100*9291985bSStephan Aßmus BRect rect = BSlider::ThumbFrame();
101*9291985bSStephan Aßmus rect.InsetBy(2, 2);
102*9291985bSStephan Aßmus rect.bottom += 1;
103*9291985bSStephan Aßmus #else
104b000c602SStephan Aßmus BRect rect(BarFrame());
105b000c602SStephan Aßmus # if KNOB_EMBEDDED
106b000c602SStephan Aßmus // Knob embedded in bar frame
107b000c602SStephan Aßmus rect.InsetBy(0, 1);
108b000c602SStephan Aßmus # else
109b000c602SStephan Aßmus // Knob extends outside the bar frame
110b000c602SStephan Aßmus rect.InsetBy(0, -1);
111b000c602SStephan Aßmus # endif
112b000c602SStephan Aßmus rect.InsetBy(rect.Height() / 2, 0);
113b000c602SStephan Aßmus rect.left = rect.left + rect.Width() * Position() - rect.Height() / 2;
114b000c602SStephan Aßmus rect.right = rect.left + rect.Height();
115*9291985bSStephan Aßmus #endif
116*9291985bSStephan Aßmus
117b000c602SStephan Aßmus return rect;
118b000c602SStephan Aßmus }
119b000c602SStephan Aßmus
120b000c602SStephan Aßmus
121b000c602SStephan Aßmus void
DrawThumb()122b000c602SStephan Aßmus VolumeSlider::DrawThumb()
123b000c602SStephan Aßmus {
124*9291985bSStephan Aßmus #if ROUND_KNOB
125b000c602SStephan Aßmus // Draw a round thumb
126b000c602SStephan Aßmus BRect rect(ThumbFrame());
127b000c602SStephan Aßmus
128b000c602SStephan Aßmus rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
129b000c602SStephan Aßmus rgb_color frameLightColor;
130b000c602SStephan Aßmus rgb_color frameShadowColor;
131b000c602SStephan Aßmus rgb_color shadowColor = (rgb_color){ 0, 0, 0, 60 };
132b000c602SStephan Aßmus
133b000c602SStephan Aßmus float topTint = 0.49;
134b000c602SStephan Aßmus float middleTint1 = 0.62;
135b000c602SStephan Aßmus float middleTint2 = 0.76;
136b000c602SStephan Aßmus float bottomTint = 0.90;
137b000c602SStephan Aßmus
1380fc56ed5SStephan Aßmus if (!IsEnabled()) {
139b000c602SStephan Aßmus topTint = (topTint + B_NO_TINT) / 2;
140b000c602SStephan Aßmus middleTint1 = (middleTint1 + B_NO_TINT) / 2;
141b000c602SStephan Aßmus middleTint2 = (middleTint2 + B_NO_TINT) / 2;
142b000c602SStephan Aßmus bottomTint = (bottomTint + B_NO_TINT) / 2;
143b000c602SStephan Aßmus shadowColor = (rgb_color){ 0, 0, 0, 30 };
1440fc56ed5SStephan Aßmus }
1450fc56ed5SStephan Aßmus
146b000c602SStephan Aßmus // Draw shadow
147b000c602SStephan Aßmus #if !KNOB_EMBEDDED
148b000c602SStephan Aßmus rect.left++;
149b000c602SStephan Aßmus rect.top++;
150b000c602SStephan Aßmus SetDrawingMode(B_OP_ALPHA);
151b000c602SStephan Aßmus SetHighColor(shadowColor);
152b000c602SStephan Aßmus FillEllipse(rect);
153b000c602SStephan Aßmus
154b000c602SStephan Aßmus // Draw thumb shape
155b000c602SStephan Aßmus rect.OffsetBy(-1, -1);
156b000c602SStephan Aßmus #endif
157b000c602SStephan Aßmus
158b000c602SStephan Aßmus if (IsFocus()) {
159b000c602SStephan Aßmus // focused
160b000c602SStephan Aßmus frameLightColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
161b000c602SStephan Aßmus frameShadowColor = frameLightColor;
162b000c602SStephan Aßmus } else {
163b000c602SStephan Aßmus // figure out the tints to be used
164b000c602SStephan Aßmus float frameLightTint;
165b000c602SStephan Aßmus float frameShadowTint;
166b000c602SStephan Aßmus
167b000c602SStephan Aßmus if (!IsEnabled()) {
168b000c602SStephan Aßmus frameLightTint = 1.30;
169b000c602SStephan Aßmus frameShadowTint = 1.35;
170b000c602SStephan Aßmus shadowColor.alpha = 30;
171b000c602SStephan Aßmus } else {
172b000c602SStephan Aßmus frameLightTint = 1.6;
173b000c602SStephan Aßmus frameShadowTint = 1.65;
1740fc56ed5SStephan Aßmus }
1750fc56ed5SStephan Aßmus
176b000c602SStephan Aßmus frameLightColor = tint_color(base, frameLightTint);
177b000c602SStephan Aßmus frameShadowColor = tint_color(base, frameShadowTint);
1780fc56ed5SStephan Aßmus }
1790fc56ed5SStephan Aßmus
180b000c602SStephan Aßmus BGradientLinear frameGradient;
181b000c602SStephan Aßmus frameGradient.AddColor(frameShadowColor, 0);
182b000c602SStephan Aßmus frameGradient.AddColor(frameLightColor, 255);
183b000c602SStephan Aßmus frameGradient.SetStart(rect.LeftTop());
184b000c602SStephan Aßmus frameGradient.SetEnd(rect.RightBottom());
185b000c602SStephan Aßmus
186b000c602SStephan Aßmus FillEllipse(rect, frameGradient);
187b000c602SStephan Aßmus rect.InsetBy(1, 1);
188b000c602SStephan Aßmus
189b000c602SStephan Aßmus // frameGradient.MakeEmpty();
190b000c602SStephan Aßmus // frameGradient.AddColor(borderColor, 0);
191b000c602SStephan Aßmus // frameGradient.AddColor(tint_color(borderColor, 0.8), 255);
192b000c602SStephan Aßmus // view->FillEllipse(rect, frameGradient);
193b000c602SStephan Aßmus // rect.InsetBy(1, 1);
194b000c602SStephan Aßmus
195b000c602SStephan Aßmus BGradientLinear gradient;
196b000c602SStephan Aßmus if (!IsEnabled()) {
197b000c602SStephan Aßmus gradient.AddColor(tint_color(base, topTint), 0);
198b000c602SStephan Aßmus gradient.AddColor(tint_color(base, bottomTint), 255);
199b000c602SStephan Aßmus } else {
200b000c602SStephan Aßmus gradient.AddColor(tint_color(base, topTint), 0);
201b000c602SStephan Aßmus gradient.AddColor(tint_color(base, middleTint1), 132);
202b000c602SStephan Aßmus gradient.AddColor(tint_color(base, middleTint2), 136);
203b000c602SStephan Aßmus gradient.AddColor(tint_color(base, bottomTint), 255);
204b000c602SStephan Aßmus }
205b000c602SStephan Aßmus gradient.SetStart(rect.LeftTop());
206b000c602SStephan Aßmus gradient.SetEnd(rect.LeftBottom());
207b000c602SStephan Aßmus FillEllipse(rect, gradient);
208*9291985bSStephan Aßmus #else
209*9291985bSStephan Aßmus BSlider::DrawThumb();
210*9291985bSStephan Aßmus #endif
211*9291985bSStephan Aßmus }
212*9291985bSStephan Aßmus
213*9291985bSStephan Aßmus
214*9291985bSStephan Aßmus BSize
MinSize()215*9291985bSStephan Aßmus VolumeSlider::MinSize()
216*9291985bSStephan Aßmus {
217*9291985bSStephan Aßmus BSize size = BSlider::MinSize();
218*9291985bSStephan Aßmus size.width *= 2;
219*9291985bSStephan Aßmus return size;
2200fc56ed5SStephan Aßmus }
2210fc56ed5SStephan Aßmus
2220fc56ed5SStephan Aßmus
2230fc56ed5SStephan Aßmus void
SetMuted(bool mute)2240fc56ed5SStephan Aßmus VolumeSlider::SetMuted(bool mute)
2250fc56ed5SStephan Aßmus {
2260fc56ed5SStephan Aßmus if (mute == fMuted)
2270fc56ed5SStephan Aßmus return;
2280fc56ed5SStephan Aßmus
2290fc56ed5SStephan Aßmus fMuted = mute;
230b000c602SStephan Aßmus
231b000c602SStephan Aßmus rgb_color fillColor = kGreen;
232b000c602SStephan Aßmus if (fMuted) {
233b000c602SStephan Aßmus fillColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
234b000c602SStephan Aßmus B_DARKEN_2_TINT);
235b000c602SStephan Aßmus }
236b000c602SStephan Aßmus
237b000c602SStephan Aßmus UseFillColor(true, &fillColor);
238b000c602SStephan Aßmus
2390fc56ed5SStephan Aßmus Invalidate();
2400fc56ed5SStephan Aßmus }
2410fc56ed5SStephan Aßmus
242b000c602SStephan Aßmus
243b000c602SStephan Aßmus float
PreferredBarThickness() const244341ea11eSStephan Aßmus VolumeSlider::PreferredBarThickness() const
245341ea11eSStephan Aßmus {
246341ea11eSStephan Aßmus #if KNOB_EMBEDDED
247341ea11eSStephan Aßmus return 10.0f;
248341ea11eSStephan Aßmus #else
249341ea11eSStephan Aßmus return 8.0f;
250341ea11eSStephan Aßmus #endif
251341ea11eSStephan Aßmus }
252341ea11eSStephan Aßmus
253341ea11eSStephan Aßmus
254341ea11eSStephan Aßmus float
_PointForValue(int32 value) const255b000c602SStephan Aßmus VolumeSlider::_PointForValue(int32 value) const
2560fc56ed5SStephan Aßmus {
257b000c602SStephan Aßmus int32 min, max;
258b000c602SStephan Aßmus GetLimits(&min, &max);
2590fc56ed5SStephan Aßmus
260b000c602SStephan Aßmus if (Orientation() == B_HORIZONTAL) {
261b000c602SStephan Aßmus return ceilf(1.0f * (value - min) / (max - min)
262b000c602SStephan Aßmus * (BarFrame().Width() - 2) + BarFrame().left + 1);
2630fc56ed5SStephan Aßmus }
2640fc56ed5SStephan Aßmus
265b000c602SStephan Aßmus return ceilf(BarFrame().top - 1.0f * (value - min) / (max - min)
266b000c602SStephan Aßmus * BarFrame().Height());
2670fc56ed5SStephan Aßmus }
2680fc56ed5SStephan Aßmus
269b000c602SStephan Aßmus
270