| Index: chrome/browser/ui/views/sidebar/sidebar_base_tab.cc
|
| ===================================================================
|
| --- chrome/browser/ui/views/sidebar/sidebar_base_tab.cc (revision 0)
|
| +++ chrome/browser/ui/views/sidebar/sidebar_base_tab.cc (revision 0)
|
| @@ -0,0 +1,321 @@
|
| +// Copyright (c) 2010 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/sidebar/sidebar_base_tab.h"
|
| +
|
| +#include <limits>
|
| +
|
| +#include "base/utf_string_conversions.h"
|
| +#include "chrome/browser/tab_contents/tab_contents.h"
|
| +#include "chrome/browser/ui/view_ids.h"
|
| +#include "chrome/browser/ui/views/sidebar/sidebar_tab_controller.h"
|
| +#include "gfx/canvas_skia.h"
|
| +#include "gfx/favicon_size.h"
|
| +#include "grit/app_resources.h"
|
| +#include "grit/generated_resources.h"
|
| +#include "grit/theme_resources.h"
|
| +#include "ui/base/animation/animation_container.h"
|
| +#include "ui/base/animation/linear_animation.h"
|
| +#include "ui/base/animation/slide_animation.h"
|
| +#include "ui/base/animation/throb_animation.h"
|
| +#include "ui/base/resource/resource_bundle.h"
|
| +#include "ui/base/theme_provider.h"
|
| +
|
| +namespace {
|
| +
|
| +// How long the pulse throb takes.
|
| +const int kPulseDurationMs = 200;
|
| +
|
| +// How long the hover state takes.
|
| +const int kHoverDurationMs = 90;
|
| +
|
| +// How opaque to make the hover state (out of 1).
|
| +const double kHoverOpacity = 0.33;
|
| +
|
| +} // namespace
|
| +
|
| +// A custom animation subclass to manage the icon crash animation.
|
| +class SidebarBaseTab::IconCrashAnimation : public ui::LinearAnimation,
|
| + public ui::AnimationDelegate {
|
| + public:
|
| + explicit IconCrashAnimation(SidebarBaseTab* target)
|
| + : ALLOW_THIS_IN_INITIALIZER_LIST(LinearAnimation(1000, 25, this)),
|
| + target_(target) {
|
| + }
|
| + virtual ~IconCrashAnimation() {}
|
| +
|
| + // ui::AnimationDelegate overrides:
|
| + virtual void AnimateToState(double state) {
|
| + const double kHidingOffset = 27;
|
| +
|
| + if (state < .5) {
|
| + target_->SetIconHidingOffset(
|
| + static_cast<int>(floor(kHidingOffset * 2.0 * state)));
|
| + } else {
|
| + target_->DisplayCrashedIcon();
|
| + target_->SetIconHidingOffset(
|
| + static_cast<int>(
|
| + floor(kHidingOffset - ((state - .5) * 2.0 * kHidingOffset))));
|
| + }
|
| + }
|
| +
|
| + // ui::AnimationDelegate overrides:
|
| + virtual void AnimationCanceled(const ui::Animation* animation) {
|
| + target_->SetIconHidingOffset(0);
|
| + }
|
| +
|
| + private:
|
| + SidebarBaseTab* const target_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(IconCrashAnimation);
|
| +};
|
| +
|
| +SidebarBaseTab::SidebarBaseTab(SidebarTabController* controller)
|
| + : controller_(controller),
|
| + closing_(false),
|
| + icon_hiding_offset_(0),
|
| + should_display_crashed_icon_(false),
|
| + loading_animation_frame_(0) {
|
| + DCHECK(controller_);
|
| +
|
| + SetID(VIEW_ID_SIDEBAR_TAB);
|
| +}
|
| +
|
| +SidebarBaseTab::~SidebarBaseTab() {
|
| +}
|
| +
|
| +// views::View overrides.
|
| +
|
| +void SidebarBaseTab::OnMouseEntered(const views::MouseEvent& e) {
|
| + if (!hover_animation_.get()) {
|
| + hover_animation_.reset(new ui::SlideAnimation(this));
|
| + hover_animation_->SetContainer(animation_container_.get());
|
| + hover_animation_->SetSlideDuration(kHoverDurationMs);
|
| + }
|
| + hover_animation_->SetTweenType(ui::Tween::EASE_OUT);
|
| + hover_animation_->Show();
|
| +}
|
| +
|
| +void SidebarBaseTab::OnMouseExited(const views::MouseEvent& e) {
|
| + hover_animation_->SetTweenType(ui::Tween::EASE_IN);
|
| + hover_animation_->Hide();
|
| +}
|
| +
|
| +bool SidebarBaseTab::OnMousePressed(const views::MouseEvent& event) {
|
| + if (event.IsOnlyLeftMouseButton())
|
| + controller_->SelectTab(this);
|
| + return true;
|
| +}
|
| +
|
| +bool SidebarBaseTab::GetTooltipText(const gfx::Point& p,
|
| + std::wstring* tooltip) {
|
| + if (data_.title.empty())
|
| + return false;
|
| + *tooltip = UTF16ToWide(data_.title);
|
| + return true;
|
| +}
|
| +
|
| +AccessibilityTypes::Role SidebarBaseTab::GetAccessibleRole() {
|
| + return AccessibilityTypes::ROLE_PAGETAB;
|
| +}
|
| +
|
| +// SidebarBaseTab, public.
|
| +
|
| +void SidebarBaseTab::SetData(const SidebarTabRendererData& data) {
|
| + SidebarTabRendererData old(data_);
|
| + data_ = data;
|
| +
|
| + bool is_performing_crash_animation =
|
| + crash_animation_.get() && crash_animation_->is_animating();
|
| + if (data_.crashed) {
|
| + if (!should_display_crashed_icon_ && !is_performing_crash_animation)
|
| + StartCrashAnimation();
|
| + } else {
|
| + if (is_performing_crash_animation)
|
| + StopCrashAnimation();
|
| + ResetCrashedIcon();
|
| + }
|
| +
|
| + // Sets the accessible name for the tab.
|
| + SetAccessibleName(data_.title);
|
| +
|
| + DCHECK(data_.icon.isNull() ||
|
| + (data_.icon.width() == kFavIconSize &&
|
| + data_.icon.height() == kFavIconSize));
|
| +
|
| + DataChanged(old);
|
| +
|
| + Layout();
|
| +}
|
| +
|
| +bool SidebarBaseTab::UpdateLoadingAnimation(
|
| + SidebarTabRendererData::NetworkState state) {
|
| + if (state == data_.network_state &&
|
| + state == SidebarTabRendererData::NETWORK_STATE_NONE) {
|
| + // If the network state is none and hasn't changed, do nothing. Otherwise
|
| + // we need to advance the animation frame.
|
| + return false;
|
| + }
|
| +
|
| + SidebarTabRendererData::NetworkState old_state = data_.network_state;
|
| + data_.network_state = state;
|
| + AdvanceLoadingAnimation(old_state, state);
|
| + return true;
|
| +}
|
| +
|
| +void SidebarBaseTab::StartPulse() {
|
| + if (!pulse_animation_.get()) {
|
| + pulse_animation_.reset(new ui::ThrobAnimation(this));
|
| + pulse_animation_->SetSlideDuration(kPulseDurationMs);
|
| + if (animation_container_.get())
|
| + pulse_animation_->SetContainer(animation_container_.get());
|
| + }
|
| + pulse_animation_->Reset();
|
| + pulse_animation_->StartThrobbing(std::numeric_limits<int>::max());
|
| +}
|
| +
|
| +void SidebarBaseTab::StopPulse() {
|
| + if (!pulse_animation_.get())
|
| + return;
|
| +
|
| + pulse_animation_->Stop(); // Do stop so we get notified.
|
| + pulse_animation_.reset(NULL);
|
| +}
|
| +
|
| +bool SidebarBaseTab::IsSelected() const {
|
| + return controller_->IsTabSelected(this);
|
| +}
|
| +
|
| +bool SidebarBaseTab::IsExpanded() const {
|
| + return controller_->IsSidebarExpanded();
|
| +}
|
| +
|
| +// SidebarBaseTab, protected.
|
| +
|
| +void SidebarBaseTab::AdvanceLoadingAnimation(
|
| + SidebarTabRendererData::NetworkState old_state,
|
| + SidebarTabRendererData::NetworkState state) {
|
| + static bool initialized = false;
|
| + static int loading_animation_frame_count = 0;
|
| + static int waiting_animation_frame_count = 0;
|
| + static int waiting_to_loading_frame_count_ratio = 0;
|
| + if (!initialized) {
|
| + initialized = true;
|
| + ResourceBundle& rb = ResourceBundle::GetSharedInstance();
|
| + SkBitmap loading_animation(*rb.GetBitmapNamed(IDR_THROBBER));
|
| + loading_animation_frame_count =
|
| + loading_animation.width() / loading_animation.height();
|
| + SkBitmap waiting_animation(*rb.GetBitmapNamed(IDR_THROBBER_WAITING));
|
| + waiting_animation_frame_count =
|
| + waiting_animation.width() / waiting_animation.height();
|
| + waiting_to_loading_frame_count_ratio =
|
| + waiting_animation_frame_count / loading_animation_frame_count;
|
| + }
|
| +
|
| + // The waiting animation is the reverse of the loading animation, but at a
|
| + // different rate - the following reverses and scales the animation_frame_
|
| + // so that the frame is at an equivalent position when going from one
|
| + // animation to the other.
|
| + if (state != old_state) {
|
| + loading_animation_frame_ = loading_animation_frame_count -
|
| + (loading_animation_frame_ / waiting_to_loading_frame_count_ratio);
|
| + }
|
| +
|
| + if (state != SidebarTabRendererData::NETWORK_STATE_NONE) {
|
| + loading_animation_frame_ = (loading_animation_frame_ + 1) %
|
| + ((state == SidebarTabRendererData::NETWORK_STATE_WAITING) ?
|
| + waiting_animation_frame_count : loading_animation_frame_count);
|
| + } else {
|
| + loading_animation_frame_ = 0;
|
| + }
|
| + SchedulePaint();
|
| +}
|
| +
|
| +double SidebarBaseTab::GetThrobValue() {
|
| + if (pulse_animation_.get() && pulse_animation_->is_animating())
|
| + return pulse_animation_->GetCurrentValue() * kHoverOpacity;
|
| +
|
| + return hover_animation_.get() ?
|
| + kHoverOpacity * hover_animation_->GetCurrentValue() : 0;
|
| +}
|
| +
|
| +void SidebarBaseTab::PaintIcon(gfx::Canvas* canvas, int x, int y, int alpha) {
|
| + SkPaint paint;
|
| + paint.setAlpha(alpha);
|
| + if (data().network_state != SidebarTabRendererData::NETWORK_STATE_NONE) {
|
| + ThemeProvider* tp = GetThemeProvider();
|
| + SkBitmap frames(*tp->GetBitmapNamed(
|
| + data().network_state == SidebarTabRendererData::NETWORK_STATE_WAITING ?
|
| + IDR_THROBBER_WAITING : IDR_THROBBER));
|
| + int image_size = frames.height();
|
| + int image_offset = loading_animation_frame_ * image_size;
|
| + int dst_y = (height() - image_size) / 2;
|
| + canvas->DrawBitmapInt(frames, image_offset, 0, image_size,
|
| + image_size, x, dst_y, image_size, image_size,
|
| + false, paint);
|
| + } else {
|
| + canvas->Save();
|
| + canvas->ClipRectInt(0, 0, width(), height());
|
| + if (should_display_crashed_icon_) {
|
| + ResourceBundle& rb = ResourceBundle::GetSharedInstance();
|
| + SkBitmap crashed_icon(*rb.GetBitmapNamed(IDR_SAD_FAVICON));
|
| + canvas->DrawBitmapInt(crashed_icon, 0, 0, crashed_icon.width(),
|
| + crashed_icon.height(), x,
|
| + (height() - crashed_icon.height()) / 2 + icon_hiding_offset_,
|
| + kFavIconSize, kFavIconSize, true, paint);
|
| + } else {
|
| + if (!data().icon.isNull()) {
|
| + int size = data().icon.width();
|
| + canvas->DrawBitmapInt(data().icon, 0, 0,
|
| + data().icon.width(),
|
| + data().icon.height(),
|
| + x, y + icon_hiding_offset_, size, size,
|
| + true, paint);
|
| + }
|
| + }
|
| + canvas->Restore();
|
| + }
|
| +}
|
| +
|
| +// ui::AnimationDelegate overrides.
|
| +
|
| +void SidebarBaseTab::AnimationProgressed(const ui::Animation* animation) {
|
| + SchedulePaint();
|
| +}
|
| +
|
| +void SidebarBaseTab::AnimationCanceled(const ui::Animation* animation) {
|
| + SchedulePaint();
|
| +}
|
| +
|
| +void SidebarBaseTab::AnimationEnded(const ui::Animation* animation) {
|
| + SchedulePaint();
|
| +}
|
| +
|
| +// SidebarBaseTab, private.
|
| +
|
| +void SidebarBaseTab::SetIconHidingOffset(int offset) {
|
| + icon_hiding_offset_ = offset;
|
| + SchedulePaint();
|
| +}
|
| +
|
| +void SidebarBaseTab::DisplayCrashedIcon() {
|
| + should_display_crashed_icon_ = true;
|
| +}
|
| +
|
| +void SidebarBaseTab::ResetCrashedIcon() {
|
| + should_display_crashed_icon_ = false;
|
| +}
|
| +
|
| +void SidebarBaseTab::StartCrashAnimation() {
|
| + if (!crash_animation_.get())
|
| + crash_animation_.reset(new IconCrashAnimation(this));
|
| + crash_animation_->Stop();
|
| + crash_animation_->Start();
|
| +}
|
| +
|
| +void SidebarBaseTab::StopCrashAnimation() {
|
| + if (crash_animation_.get())
|
| + crash_animation_->Stop();
|
| +}
|
| +
|
|
|
| Property changes on: chrome\browser\ui\views\sidebar\sidebar_base_tab.cc
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|