| Index: chrome/browser/ui/views/tabs/media_indicator_button.cc
|
| diff --git a/chrome/browser/ui/views/tabs/media_indicator_button.cc b/chrome/browser/ui/views/tabs/media_indicator_button.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..afcad3d155600b92ee34aeb7802eefd435f603af
|
| --- /dev/null
|
| +++ b/chrome/browser/ui/views/tabs/media_indicator_button.cc
|
| @@ -0,0 +1,159 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "chrome/browser/ui/views/tabs/media_indicator_button.h"
|
| +
|
| +#include "chrome/browser/ui/views/tabs/tab.h"
|
| +#include "chrome/browser/ui/views/tabs/tab_controller.h"
|
| +#include "chrome/browser/ui/views/tabs/tab_renderer_data.h"
|
| +#include "content/public/browser/user_metrics.h"
|
| +#include "ui/gfx/animation/animation_delegate.h"
|
| +#include "ui/gfx/canvas.h"
|
| +#include "ui/gfx/image/image.h"
|
| +
|
| +using base::UserMetricsAction;
|
| +
|
| +const char MediaIndicatorButton::kViewClassName[] = "MediaIndicatorButton";
|
| +
|
| +class MediaIndicatorButton::FadeAnimationDelegate
|
| + : public gfx::AnimationDelegate {
|
| + public:
|
| + explicit FadeAnimationDelegate(MediaIndicatorButton* button)
|
| + : button_(button) {}
|
| + virtual ~FadeAnimationDelegate() {}
|
| +
|
| + private:
|
| + // gfx::AnimationDelegate
|
| + virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE {
|
| + button_->SchedulePaint();
|
| + }
|
| +
|
| + virtual void AnimationCanceled(const gfx::Animation* animation) OVERRIDE {
|
| + button_->showing_media_state_ = button_->media_state_;
|
| + button_->SchedulePaint();
|
| + }
|
| +
|
| + virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE {
|
| + button_->showing_media_state_ = button_->media_state_;
|
| + button_->SchedulePaint();
|
| + }
|
| +
|
| + MediaIndicatorButton* const button_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(FadeAnimationDelegate);
|
| +};
|
| +
|
| +MediaIndicatorButton::MediaIndicatorButton()
|
| + : views::ImageButton(NULL),
|
| + media_state_(TAB_MEDIA_STATE_NONE),
|
| + showing_media_state_(TAB_MEDIA_STATE_NONE) {
|
| + SetEventTargeter(
|
| + scoped_ptr<views::ViewTargeter>(new views::ViewTargeter(this)));
|
| +}
|
| +
|
| +MediaIndicatorButton::~MediaIndicatorButton() {}
|
| +
|
| +void MediaIndicatorButton::TransitionToMediaState(TabMediaState next_state) {
|
| + if (next_state == media_state_)
|
| + return;
|
| +
|
| + if (next_state != TAB_MEDIA_STATE_NONE) {
|
| + const gfx::ImageSkia* const indicator_image =
|
| + chrome::GetTabMediaIndicatorImage(next_state).ToImageSkia();
|
| + SetImage(views::CustomButton::STATE_NORMAL, indicator_image);
|
| + SetImage(views::CustomButton::STATE_DISABLED, indicator_image);
|
| + const gfx::ImageSkia* const affordance_image =
|
| + chrome::GetTabMediaIndicatorAffordanceImage(next_state).ToImageSkia();
|
| + SetImage(views::CustomButton::STATE_HOVERED, affordance_image);
|
| + SetImage(views::CustomButton::STATE_PRESSED, affordance_image);
|
| + }
|
| +
|
| + if ((media_state_ == TAB_MEDIA_STATE_AUDIO_PLAYING &&
|
| + next_state == TAB_MEDIA_STATE_AUDIO_MUTING) ||
|
| + (media_state_ == TAB_MEDIA_STATE_AUDIO_MUTING &&
|
| + next_state == TAB_MEDIA_STATE_AUDIO_PLAYING) ||
|
| + (media_state_ == TAB_MEDIA_STATE_AUDIO_MUTING &&
|
| + next_state == TAB_MEDIA_STATE_NONE)) {
|
| + // Instant user feedback: No fade animation.
|
| + showing_media_state_ = next_state;
|
| + fade_animation_.reset();
|
| + } else {
|
| + if (next_state == TAB_MEDIA_STATE_NONE)
|
| + showing_media_state_ = media_state_; // Fading-out indicator.
|
| + else
|
| + showing_media_state_ = next_state; // Fading-in to next indicator.
|
| + fade_animation_ = chrome::CreateTabMediaIndicatorFadeAnimation(next_state);
|
| + if (!fade_animation_delegate_)
|
| + fade_animation_delegate_.reset(new FadeAnimationDelegate(this));
|
| + fade_animation_->set_delegate(fade_animation_delegate_.get());
|
| + fade_animation_->Start();
|
| + }
|
| +
|
| + SetEnabled(chrome::IsTabAudioMutingFeatureEnabled() &&
|
| + (next_state == TAB_MEDIA_STATE_AUDIO_PLAYING ||
|
| + next_state == TAB_MEDIA_STATE_AUDIO_MUTING));
|
| +
|
| + // An indicator state change should be made visible immediately, instead of
|
| + // the user being surprised when their mouse leaves the button.
|
| + if (state() == views::CustomButton::STATE_HOVERED) {
|
| + SetState(enabled() ? views::CustomButton::STATE_NORMAL :
|
| + views::CustomButton::STATE_DISABLED);
|
| + }
|
| +
|
| + media_state_ = next_state;
|
| +
|
| + // Note: The calls to SetImage(), SetEnabled(), and SetState() above will call
|
| + // SchedulePaint() if necessary.
|
| +}
|
| +
|
| +const char* MediaIndicatorButton::GetClassName() const {
|
| + return kViewClassName;
|
| +}
|
| +
|
| +views::View* MediaIndicatorButton::GetTooltipHandlerForPoint(
|
| + const gfx::Point& point) {
|
| + return NULL; // Tab (the parent View) provides the tooltip.
|
| +}
|
| +
|
| +bool MediaIndicatorButton::OnMouseDragged(const ui::MouseEvent& event) {
|
| + const ButtonState previous_state = state();
|
| + const bool ret = ImageButton::OnMouseDragged(event);
|
| + if (previous_state != views::CustomButton::STATE_NORMAL &&
|
| + state() == views::CustomButton::STATE_NORMAL)
|
| + content::RecordAction(UserMetricsAction("MediaIndicatorButton_Dragged"));
|
| + return ret;
|
| +}
|
| +
|
| +void MediaIndicatorButton::OnPaint(gfx::Canvas* canvas) {
|
| + double opaqueness =
|
| + fade_animation_ ? fade_animation_->GetCurrentValue() : 1.0;
|
| + if (media_state_ == TAB_MEDIA_STATE_NONE)
|
| + opaqueness = 1.0 - opaqueness; // Fading out, not in.
|
| + if (opaqueness < 1.0)
|
| + canvas->SaveLayerAlpha(opaqueness * SK_AlphaOPAQUE);
|
| + ImageButton::OnPaint(canvas);
|
| + if (opaqueness < 1.0)
|
| + canvas->Restore();
|
| +}
|
| +
|
| +bool MediaIndicatorButton::DoesIntersectRect(const views::View* target,
|
| + const gfx::Rect& rect) const {
|
| + // If this button is not enabled, Tab (the parent View) handles all mouse
|
| + // events.
|
| + return enabled() &&
|
| + views::ViewTargeterDelegate::DoesIntersectRect(target, rect);
|
| +}
|
| +
|
| +void MediaIndicatorButton::NotifyClick(const ui::Event& event) {
|
| + if (media_state_ == TAB_MEDIA_STATE_AUDIO_PLAYING)
|
| + content::RecordAction(UserMetricsAction("MediaIndicatorButton_Mute"));
|
| + else if (media_state_ == TAB_MEDIA_STATE_AUDIO_MUTING)
|
| + content::RecordAction(UserMetricsAction("MediaIndicatorButton_Unmute"));
|
| + else
|
| + NOTREACHED();
|
| +
|
| + DCHECK(parent() && !strcmp(parent()->GetClassName(), Tab::kViewClassName));
|
| + Tab* const tab = static_cast<Tab*>(parent());
|
| + tab->controller()->ToggleTabAudioMute(tab);
|
| +}
|
|
|