root/src/apps/mediaplayer/interface/PlayPauseButton.cpp
/*
 * Copyright 2010, Stephan Aßmus <superstippi@gmx.de>.
 * Distributed under the terms of the MIT License.
 */


#include "PlayPauseButton.h"

#include <GradientLinear.h>
#include <LayoutUtils.h>
#include <Shape.h>


static const rgb_color kGreen = (rgb_color){ 116, 224, 0, 255 };


// constructor
PlayPauseButton::PlayPauseButton(const char* name,
                BShape* playSymbolShape, BShape* pauseSymbolShape, BMessage* message,
                uint32 borders)
        :
        SymbolButton(name, NULL, message, borders),
        fPlaySymbol(playSymbolShape),
        fPauseSymbol(pauseSymbolShape),
        fPlaybackState(kStopped)
{
}


PlayPauseButton::~PlayPauseButton()
{
        delete fPlaySymbol;
        delete fPauseSymbol;
}


void
PlayPauseButton::Draw(BRect updateRect)
{
        SymbolButton::Draw(updateRect);

        rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
        rgb_color active = (rgb_color){ 116, 224, 0, 255 };

        if (IsEnabled()) {
                if (Value() == B_CONTROL_ON)
                        base = tint_color(base, (B_DARKEN_4_TINT + B_DARKEN_MAX_TINT) / 2);
                else
                        base = tint_color(base, B_DARKEN_4_TINT);
        } else {
                if (Value() == B_CONTROL_ON)
                        base = tint_color(base, B_DARKEN_2_TINT);
                else
                        base = tint_color(base, B_DARKEN_1_TINT);
        }
        BRect bounds(Bounds());
        BRect pauseBounds = fPauseSymbol->Bounds();
        BRect playBounds = fPlaySymbol->Bounds();

        BPoint offset;
        float spacing = pauseBounds.Height() / 4;
        offset.x = (bounds.left + bounds.right) / 2;
        offset.y = (bounds.top + bounds.bottom) / 2;
        offset.x -= (pauseBounds.Width() + playBounds.Width() + spacing) / 2;
        offset.y -= pauseBounds.Height() / 2;
        offset.x = floorf(offset.x - playBounds.left + 0.5);
        offset.y = ceilf(offset.y - pauseBounds.top);
        if (Value() == B_CONTROL_ON) {
                offset.x += 1;
                offset.y += 1;
        }

        bool playActive = IsEnabled()
                && ((fPlaybackState == kPlaying && Value() == B_CONTROL_OFF)
                        || (fPlaybackState == kPaused && Value() == B_CONTROL_ON));
        bool pauseActive = IsEnabled()
                && ((fPlaybackState == kPaused && Value() == B_CONTROL_OFF)
                        || (fPlaybackState == kPlaying && Value() == B_CONTROL_ON));

        MovePenTo(offset);
        BGradientLinear gradient;
        if (playActive) {
                gradient.AddColor(active, 0);
                gradient.AddColor(tint_color(active, B_LIGHTEN_1_TINT), 255);
        } else {
                gradient.AddColor(tint_color(base, B_DARKEN_1_TINT), 0);
                gradient.AddColor(base, 255);
        }
        gradient.SetStart(offset);
        offset.y += playBounds.Height();
        gradient.SetEnd(offset);
        FillShape(fPlaySymbol, gradient);
        if (playActive) {
                SetHighColor(tint_color(active, B_DARKEN_3_TINT));
                MovePenBy(0.5, 0.5);
                StrokeShape(fPlaySymbol);
        }

        offset.y -= playBounds.Height();
        offset.x += ceilf(playBounds.Width() + spacing);
        MovePenTo(offset);
        gradient.MakeEmpty();
        if (pauseActive) {
                gradient.AddColor(active, 0);
                gradient.AddColor(tint_color(active, B_LIGHTEN_1_TINT), 255);
        } else {
                gradient.AddColor(tint_color(base, B_DARKEN_1_TINT), 0);
                gradient.AddColor(base, 255);
        }
        gradient.SetStart(offset);
        offset.y += playBounds.Height();
        gradient.SetEnd(offset);
        FillShape(fPauseSymbol, gradient);
        if (pauseActive) {
                SetHighColor(tint_color(active, B_DARKEN_3_TINT));
                MovePenBy(0.5, 0.5);
                StrokeShape(fPauseSymbol);
        }
}


BSize
PlayPauseButton::MinSize()
{
        if (fPauseSymbol == NULL || fPlaySymbol == NULL)
                return BButton::MinSize();

        BSize size;
        size.width = ceilf(
                (fPlaySymbol->Bounds().Width() + fPauseSymbol->Bounds().Width())
                        * 2.5f);
        size.height = ceilf(fPauseSymbol->Bounds().Height() * 2.5f);
        return BLayoutUtils::ComposeSize(ExplicitMinSize(), size);
}


BSize
PlayPauseButton::MaxSize()
{
        BSize size(MinSize());
        size.width = ceilf(size.width * 1.5f);
        return BLayoutUtils::ComposeSize(ExplicitMaxSize(), size);
}


void
PlayPauseButton::SetPlaying()
{
        _SetPlaybackState(kPlaying);
}


void
PlayPauseButton::SetPaused()
{
        _SetPlaybackState(kPaused);
}


void
PlayPauseButton::SetStopped()
{
        _SetPlaybackState(kStopped);
}


void
PlayPauseButton::SetSymbols(BShape* playSymbolShape, BShape* pauseSymbolShape)
{
        BSize oldSize = MinSize();

        delete fPlaySymbol;
        fPlaySymbol = playSymbolShape;
        delete fPauseSymbol;
        fPauseSymbol = pauseSymbolShape;

        if (MinSize() != oldSize)
                InvalidateLayout();

        Invalidate();
}


void
PlayPauseButton::_SetPlaybackState(uint32 state)
{
        if (fPlaybackState == state)
                return;
        fPlaybackState = state;
        Invalidate();
}