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 |