/* * Copyright 2010, Stephan Aßmus . * Distributed under the terms of the MIT License. */ #include "VolumeSlider.h" #include #include #include #define KNOB_EMBEDDED 0 #define ROUND_KNOB 0 static const rgb_color kGreen = (rgb_color){ 116, 224, 0, 255 }; // constructor VolumeSlider::VolumeSlider(const char* name, int32 minValue, int32 maxValue, int32 snapValue, BMessage* message) : BSlider(name, NULL, NULL, minValue, maxValue, B_HORIZONTAL, B_BLOCK_THUMB), fMuted(false), fSnapValue(snapValue), fSnapping(false) { SetModificationMessage(message); UseFillColor(true, &kGreen); SetBarThickness(PreferredBarThickness()); } VolumeSlider::~VolumeSlider() { } void VolumeSlider::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage) { if (!IsTracking()) { BSlider::MouseMoved(where, transit, dragMessage); return; } float cursorPosition = Orientation() == B_HORIZONTAL ? where.x : where.y; if (fSnapping && cursorPosition >= fMinSnap && cursorPosition <= fMaxSnap) { // Don't move the slider, keep the current value for a few // more pixels return; } fSnapping = false; int32 oldValue = Value(); int32 newValue = ValueForPoint(where); if (oldValue == newValue) { BSlider::MouseMoved(where, transit, dragMessage); return; } // Check if there is a 0 dB transition at all if ((oldValue < fSnapValue && newValue >= fSnapValue) || (oldValue > fSnapValue && newValue <= fSnapValue)) { SetValue(fSnapValue); if (ModificationMessage() != NULL) Messenger().SendMessage(ModificationMessage()); float snapPoint = _PointForValue(fSnapValue); const float kMaxSnapOffset = 6; if (oldValue > newValue) { // movement from right to left fMinSnap = snapPoint - kMaxSnapOffset; fMaxSnap = snapPoint + 1; } else { // movement from left to right fMinSnap = snapPoint - 1; fMaxSnap = snapPoint + kMaxSnapOffset; } fSnapping = true; return; } BSlider::MouseMoved(where, transit, dragMessage); } BRect VolumeSlider::ThumbFrame() const { #if !ROUND_KNOB BRect rect = BSlider::ThumbFrame(); rect.InsetBy(2, 2); rect.bottom += 1; #else BRect rect(BarFrame()); # if KNOB_EMBEDDED // Knob embedded in bar frame rect.InsetBy(0, 1); # else // Knob extends outside the bar frame rect.InsetBy(0, -1); # endif rect.InsetBy(rect.Height() / 2, 0); rect.left = rect.left + rect.Width() * Position() - rect.Height() / 2; rect.right = rect.left + rect.Height(); #endif return rect; } void VolumeSlider::DrawThumb() { #if ROUND_KNOB // Draw a round thumb BRect rect(ThumbFrame()); rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); rgb_color frameLightColor; rgb_color frameShadowColor; rgb_color shadowColor = (rgb_color){ 0, 0, 0, 60 }; float topTint = 0.49; float middleTint1 = 0.62; float middleTint2 = 0.76; float bottomTint = 0.90; if (!IsEnabled()) { topTint = (topTint + B_NO_TINT) / 2; middleTint1 = (middleTint1 + B_NO_TINT) / 2; middleTint2 = (middleTint2 + B_NO_TINT) / 2; bottomTint = (bottomTint + B_NO_TINT) / 2; shadowColor = (rgb_color){ 0, 0, 0, 30 }; } // Draw shadow #if !KNOB_EMBEDDED rect.left++; rect.top++; SetDrawingMode(B_OP_ALPHA); SetHighColor(shadowColor); FillEllipse(rect); // Draw thumb shape rect.OffsetBy(-1, -1); #endif if (IsFocus()) { // focused frameLightColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR); frameShadowColor = frameLightColor; } else { // figure out the tints to be used float frameLightTint; float frameShadowTint; if (!IsEnabled()) { frameLightTint = 1.30; frameShadowTint = 1.35; shadowColor.alpha = 30; } else { frameLightTint = 1.6; frameShadowTint = 1.65; } frameLightColor = tint_color(base, frameLightTint); frameShadowColor = tint_color(base, frameShadowTint); } BGradientLinear frameGradient; frameGradient.AddColor(frameShadowColor, 0); frameGradient.AddColor(frameLightColor, 255); frameGradient.SetStart(rect.LeftTop()); frameGradient.SetEnd(rect.RightBottom()); FillEllipse(rect, frameGradient); rect.InsetBy(1, 1); // frameGradient.MakeEmpty(); // frameGradient.AddColor(borderColor, 0); // frameGradient.AddColor(tint_color(borderColor, 0.8), 255); // view->FillEllipse(rect, frameGradient); // rect.InsetBy(1, 1); BGradientLinear gradient; if (!IsEnabled()) { gradient.AddColor(tint_color(base, topTint), 0); gradient.AddColor(tint_color(base, bottomTint), 255); } else { gradient.AddColor(tint_color(base, topTint), 0); gradient.AddColor(tint_color(base, middleTint1), 132); gradient.AddColor(tint_color(base, middleTint2), 136); gradient.AddColor(tint_color(base, bottomTint), 255); } gradient.SetStart(rect.LeftTop()); gradient.SetEnd(rect.LeftBottom()); FillEllipse(rect, gradient); #else BSlider::DrawThumb(); #endif } BSize VolumeSlider::MinSize() { BSize size = BSlider::MinSize(); size.width *= 2; return size; } void VolumeSlider::SetMuted(bool mute) { if (mute == fMuted) return; fMuted = mute; rgb_color fillColor = kGreen; if (fMuted) { fillColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_DARKEN_2_TINT); } UseFillColor(true, &fillColor); Invalidate(); } float VolumeSlider::PreferredBarThickness() const { #if KNOB_EMBEDDED return 10.0f; #else return 8.0f; #endif } float VolumeSlider::_PointForValue(int32 value) const { int32 min, max; GetLimits(&min, &max); if (Orientation() == B_HORIZONTAL) { return ceilf(1.0f * (value - min) / (max - min) * (BarFrame().Width() - 2) + BarFrame().left + 1); } return ceilf(BarFrame().top - 1.0f * (value - min) / (max - min) * BarFrame().Height()); }