summaryrefslogtreecommitdiffstats
path: root/chrome/browser/views/status_bubble_views.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/views/status_bubble_views.cc')
-rw-r--r--chrome/browser/views/status_bubble_views.cc835
1 files changed, 0 insertions, 835 deletions
diff --git a/chrome/browser/views/status_bubble_views.cc b/chrome/browser/views/status_bubble_views.cc
deleted file mode 100644
index 234b6f0..0000000
--- a/chrome/browser/views/status_bubble_views.cc
+++ /dev/null
@@ -1,835 +0,0 @@
-// 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/views/status_bubble_views.h"
-
-#include <algorithm>
-
-#include "app/linear_animation.h"
-#include "app/resource_bundle.h"
-#include "app/text_elider.h"
-#include "base/i18n/rtl.h"
-#include "base/message_loop.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/themes/browser_theme_provider.h"
-#include "gfx/canvas_skia.h"
-#include "gfx/point.h"
-#include "googleurl/src/gurl.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "net/base/net_util.h"
-#include "third_party/skia/include/core/SkPaint.h"
-#include "third_party/skia/include/core/SkPath.h"
-#include "third_party/skia/include/core/SkRect.h"
-#include "views/controls/label.h"
-#include "views/controls/scrollbar/native_scroll_bar.h"
-#include "views/screen.h"
-#include "views/widget/root_view.h"
-#include "views/widget/widget.h"
-#include "views/window/window.h"
-
-using views::Widget;
-
-// The alpha and color of the bubble's shadow.
-static const SkColor kShadowColor = SkColorSetARGB(30, 0, 0, 0);
-
-// The roundedness of the edges of our bubble.
-static const int kBubbleCornerRadius = 4;
-
-// How close the mouse can get to the infobubble before it starts sliding
-// off-screen.
-static const int kMousePadding = 20;
-
-// The horizontal offset of the text within the status bubble, not including the
-// outer shadow ring.
-static const int kTextPositionX = 3;
-
-// The minimum horizontal space between the (right) end of the text and the edge
-// of the status bubble, not including the outer shadow ring.
-static const int kTextHorizPadding = 1;
-
-// Delays before we start hiding or showing the bubble after we receive a
-// show or hide request.
-static const int kShowDelay = 80;
-static const int kHideDelay = 250;
-
-// How long each fade should last for.
-static const int kShowFadeDurationMS = 120;
-static const int kHideFadeDurationMS = 200;
-static const int kFramerate = 25;
-
-// How long each expansion step should take.
-static const int kMinExpansionStepDurationMS = 20;
-static const int kMaxExpansionStepDurationMS = 150;
-
-// View -----------------------------------------------------------------------
-// StatusView manages the display of the bubble, applying text changes and
-// fading in or out the bubble as required.
-class StatusBubbleViews::StatusView : public views::Label,
- public LinearAnimation,
- public AnimationDelegate {
- public:
- StatusView(StatusBubble* status_bubble, views::Widget* popup,
- ThemeProvider* theme_provider)
- : ALLOW_THIS_IN_INITIALIZER_LIST(LinearAnimation(kFramerate, this)),
- stage_(BUBBLE_HIDDEN),
- style_(STYLE_STANDARD),
- ALLOW_THIS_IN_INITIALIZER_LIST(timer_factory_(this)),
- status_bubble_(status_bubble),
- popup_(popup),
- opacity_start_(0),
- opacity_end_(0),
- theme_provider_(theme_provider) {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- gfx::Font font(rb.GetFont(ResourceBundle::BaseFont));
- SetFont(font);
- }
-
- virtual ~StatusView() {
- Stop();
- CancelTimer();
- }
-
- // The bubble can be in one of many stages:
- enum BubbleStage {
- BUBBLE_HIDDEN, // Entirely BUBBLE_HIDDEN.
- BUBBLE_HIDING_FADE, // In a fade-out transition.
- BUBBLE_HIDING_TIMER, // Waiting before a fade-out.
- BUBBLE_SHOWING_TIMER, // Waiting before a fade-in.
- BUBBLE_SHOWING_FADE, // In a fade-in transition.
- BUBBLE_SHOWN // Fully visible.
- };
-
- enum BubbleStyle {
- STYLE_BOTTOM,
- STYLE_FLOATING,
- STYLE_STANDARD,
- STYLE_STANDARD_RIGHT
- };
-
- // Set the bubble text to a certain value, hides the bubble if text is
- // an empty string. Trigger animation sequence to display if
- // |should_animate_open|.
- void SetText(const string16& text, bool should_animate_open);
-
- BubbleStage GetState() const { return stage_; }
-
- void SetStyle(BubbleStyle style);
-
- BubbleStyle GetStyle() const { return style_; }
-
- // Show the bubble instantly.
- void Show();
-
- // Hide the bubble instantly.
- void Hide();
-
- // Resets any timers we have. Typically called when the user moves a
- // mouse.
- void ResetTimer();
-
- private:
- class InitialTimer;
-
- // Manage the timers that control the delay before a fade begins or ends.
- void StartTimer(int time);
- void OnTimer();
- void CancelTimer();
- void RestartTimer(int delay);
-
- // Manage the fades and starting and stopping the animations correctly.
- void StartFade(double start, double end, int duration);
- void StartHiding();
- void StartShowing();
-
- // Animation functions.
- double GetCurrentOpacity();
- void SetOpacity(double opacity);
- void AnimateToState(double state);
- void AnimationEnded(const Animation* animation);
-
- virtual void Paint(gfx::Canvas* canvas);
-
- BubbleStage stage_;
- BubbleStyle style_;
-
- ScopedRunnableMethodFactory<StatusBubbleViews::StatusView> timer_factory_;
-
- // Manager, owns us.
- StatusBubble* status_bubble_;
-
- // Handle to the widget that contains us.
- views::Widget* popup_;
-
- // The currently-displayed text.
- string16 text_;
-
- // Start and end opacities for the current transition - note that as a
- // fade-in can easily turn into a fade out, opacity_start_ is sometimes
- // a value between 0 and 1.
- double opacity_start_;
- double opacity_end_;
-
- // Holds the theme provider of the frame that created us.
- ThemeProvider* theme_provider_;
-};
-
-void StatusBubbleViews::StatusView::SetText(const string16& text,
- bool should_animate_open) {
- if (text.empty()) {
- // The string was empty.
- StartHiding();
- } else {
- // We want to show the string.
- text_ = text;
- if (should_animate_open)
- StartShowing();
- }
-
- SchedulePaint();
-}
-
-void StatusBubbleViews::StatusView::Show() {
- Stop();
- CancelTimer();
- SetOpacity(1.0);
- popup_->Show();
- stage_ = BUBBLE_SHOWN;
- PaintNow();
-}
-
-void StatusBubbleViews::StatusView::Hide() {
- Stop();
- CancelTimer();
- SetOpacity(0.0);
- text_.clear();
- popup_->Hide();
- stage_ = BUBBLE_HIDDEN;
-}
-
-void StatusBubbleViews::StatusView::StartTimer(int time) {
- if (!timer_factory_.empty())
- timer_factory_.RevokeAll();
-
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- timer_factory_.NewRunnableMethod(&StatusBubbleViews::StatusView::OnTimer),
- time);
-}
-
-void StatusBubbleViews::StatusView::OnTimer() {
- if (stage_ == BUBBLE_HIDING_TIMER) {
- stage_ = BUBBLE_HIDING_FADE;
- StartFade(1.0, 0.0, kHideFadeDurationMS);
- } else if (stage_ == BUBBLE_SHOWING_TIMER) {
- stage_ = BUBBLE_SHOWING_FADE;
- StartFade(0.0, 1.0, kShowFadeDurationMS);
- }
-}
-
-void StatusBubbleViews::StatusView::CancelTimer() {
- if (!timer_factory_.empty())
- timer_factory_.RevokeAll();
-}
-
-void StatusBubbleViews::StatusView::RestartTimer(int delay) {
- CancelTimer();
- StartTimer(delay);
-}
-
-void StatusBubbleViews::StatusView::ResetTimer() {
- if (stage_ == BUBBLE_SHOWING_TIMER) {
- // We hadn't yet begun showing anything when we received a new request
- // for something to show, so we start from scratch.
- RestartTimer(kShowDelay);
- }
-}
-
-void StatusBubbleViews::StatusView::StartFade(double start,
- double end,
- int duration) {
- opacity_start_ = start;
- opacity_end_ = end;
-
- // This will also reset the currently-occurring animation.
- SetDuration(duration);
- Start();
-}
-
-void StatusBubbleViews::StatusView::StartHiding() {
- if (stage_ == BUBBLE_SHOWN) {
- stage_ = BUBBLE_HIDING_TIMER;
- StartTimer(kHideDelay);
- } else if (stage_ == BUBBLE_SHOWING_TIMER) {
- stage_ = BUBBLE_HIDDEN;
- CancelTimer();
- } else if (stage_ == BUBBLE_SHOWING_FADE) {
- stage_ = BUBBLE_HIDING_FADE;
- // Figure out where we are in the current fade.
- double current_opacity = GetCurrentOpacity();
-
- // Start a fade in the opposite direction.
- StartFade(current_opacity, 0.0,
- static_cast<int>(kHideFadeDurationMS * current_opacity));
- }
-}
-
-void StatusBubbleViews::StatusView::StartShowing() {
- if (stage_ == BUBBLE_HIDDEN) {
- popup_->Show();
- stage_ = BUBBLE_SHOWING_TIMER;
- StartTimer(kShowDelay);
- } else if (stage_ == BUBBLE_HIDING_TIMER) {
- stage_ = BUBBLE_SHOWN;
- CancelTimer();
- } else if (stage_ == BUBBLE_HIDING_FADE) {
- // We're partway through a fade.
- stage_ = BUBBLE_SHOWING_FADE;
-
- // Figure out where we are in the current fade.
- double current_opacity = GetCurrentOpacity();
-
- // Start a fade in the opposite direction.
- StartFade(current_opacity, 1.0,
- static_cast<int>(kShowFadeDurationMS * current_opacity));
- } else if (stage_ == BUBBLE_SHOWING_TIMER) {
- // We hadn't yet begun showing anything when we received a new request
- // for something to show, so we start from scratch.
- ResetTimer();
- }
-}
-
-// Animation functions.
-double StatusBubbleViews::StatusView::GetCurrentOpacity() {
- return opacity_start_ + (opacity_end_ - opacity_start_) *
- LinearAnimation::GetCurrentValue();
-}
-
-void StatusBubbleViews::StatusView::SetOpacity(double opacity) {
- popup_->SetOpacity(static_cast<unsigned char>(opacity * 255));
- SchedulePaint();
-}
-
-void StatusBubbleViews::StatusView::AnimateToState(double state) {
- SetOpacity(GetCurrentOpacity());
-}
-
-void StatusBubbleViews::StatusView::AnimationEnded(
- const Animation* animation) {
- SetOpacity(opacity_end_);
-
- if (stage_ == BUBBLE_HIDING_FADE) {
- stage_ = BUBBLE_HIDDEN;
- popup_->Hide();
- } else if (stage_ == BUBBLE_SHOWING_FADE) {
- stage_ = BUBBLE_SHOWN;
- }
-}
-
-void StatusBubbleViews::StatusView::SetStyle(BubbleStyle style) {
- if (style_ != style) {
- style_ = style;
- SchedulePaint();
- }
-}
-
-void StatusBubbleViews::StatusView::Paint(gfx::Canvas* canvas) {
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- paint.setFlags(SkPaint::kAntiAlias_Flag);
- SkColor toolbar_color =
- theme_provider_->GetColor(BrowserThemeProvider::COLOR_TOOLBAR);
- paint.setColor(toolbar_color);
-
- gfx::Rect popup_bounds;
- popup_->GetBounds(&popup_bounds, true);
-
- // Figure out how to round the bubble's four corners.
- SkScalar rad[8];
-
- // Top Edges - if the bubble is in its bottom position (sticking downwards),
- // then we square the top edges. Otherwise, we square the edges based on the
- // position of the bubble within the window (the bubble is positioned in the
- // southeast corner in RTL and in the southwest corner in LTR).
- if (style_ == STYLE_BOTTOM) {
- // Top Left corner.
- rad[0] = 0;
- rad[1] = 0;
-
- // Top Right corner.
- rad[2] = 0;
- rad[3] = 0;
- } else {
- if (base::i18n::IsRTL() != (style_ == STYLE_STANDARD_RIGHT)) {
- // The text is RtL or the bubble is on the right side (but not both).
-
- // Top Left corner.
- rad[0] = SkIntToScalar(kBubbleCornerRadius);
- rad[1] = SkIntToScalar(kBubbleCornerRadius);
-
- // Top Right corner.
- rad[2] = 0;
- rad[3] = 0;
- } else {
- // Top Left corner.
- rad[0] = 0;
- rad[1] = 0;
-
- // Top Right corner.
- rad[2] = SkIntToScalar(kBubbleCornerRadius);
- rad[3] = SkIntToScalar(kBubbleCornerRadius);
- }
- }
-
- // Bottom edges - square these off if the bubble is in its standard position
- // (sticking upward).
- if (style_ == STYLE_STANDARD || style_ == STYLE_STANDARD_RIGHT) {
- // Bottom Right Corner.
- rad[4] = 0;
- rad[5] = 0;
-
- // Bottom Left Corner.
- rad[6] = 0;
- rad[7] = 0;
- } else {
- // Bottom Right Corner.
- rad[4] = SkIntToScalar(kBubbleCornerRadius);
- rad[5] = SkIntToScalar(kBubbleCornerRadius);
-
- // Bottom Left Corner.
- rad[6] = SkIntToScalar(kBubbleCornerRadius);
- rad[7] = SkIntToScalar(kBubbleCornerRadius);
- }
-
- // Draw the bubble's shadow.
- int width = popup_bounds.width();
- int height = popup_bounds.height();
- SkRect rect;
- rect.set(0, 0,
- SkIntToScalar(width),
- SkIntToScalar(height));
- SkPath shadow_path;
- shadow_path.addRoundRect(rect, rad, SkPath::kCW_Direction);
- SkPaint shadow_paint;
- shadow_paint.setFlags(SkPaint::kAntiAlias_Flag);
- shadow_paint.setColor(kShadowColor);
- canvas->AsCanvasSkia()->drawPath(shadow_path, shadow_paint);
-
- // Draw the bubble.
- rect.set(SkIntToScalar(kShadowThickness),
- SkIntToScalar(kShadowThickness),
- SkIntToScalar(width - kShadowThickness),
- SkIntToScalar(height - kShadowThickness));
- SkPath path;
- path.addRoundRect(rect, rad, SkPath::kCW_Direction);
- canvas->AsCanvasSkia()->drawPath(path, paint);
-
- // Draw highlight text and then the text body. In order to make sure the text
- // is aligned to the right on RTL UIs, we mirror the text bounds if the
- // locale is RTL.
- int text_width = std::min(
- views::Label::font().GetStringWidth(UTF16ToWide(text_)),
- width - (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding);
- int text_height = height - (kShadowThickness * 2);
- gfx::Rect body_bounds(kShadowThickness + kTextPositionX,
- kShadowThickness,
- std::max(0, text_width),
- std::max(0, text_height));
- body_bounds.set_x(MirroredLeftPointForRect(body_bounds));
- SkColor text_color =
- theme_provider_->GetColor(BrowserThemeProvider::COLOR_TAB_TEXT);
-
- // DrawStringInt doesn't handle alpha, so we'll do the blending ourselves.
- text_color = SkColorSetARGB(
- SkColorGetA(text_color),
- (SkColorGetR(text_color) + SkColorGetR(toolbar_color)) / 2,
- (SkColorGetG(text_color) + SkColorGetR(toolbar_color)) / 2,
- (SkColorGetB(text_color) + SkColorGetR(toolbar_color)) / 2);
- canvas->DrawStringInt(UTF16ToWide(text_),
- views::Label::font(),
- text_color,
- body_bounds.x(),
- body_bounds.y(),
- body_bounds.width(),
- body_bounds.height());
-}
-
-// StatusViewExpander ---------------------------------------------------------
-// Manages the expansion and contraction of the status bubble as it accommodates
-// URLs too long to fit in the standard bubble. Changes are passed through the
-// StatusView to paint.
-class StatusBubbleViews::StatusViewExpander : public LinearAnimation,
- public AnimationDelegate {
- public:
- StatusViewExpander(StatusBubbleViews* status_bubble,
- StatusView* status_view)
- : ALLOW_THIS_IN_INITIALIZER_LIST(LinearAnimation(kFramerate, this)),
- status_bubble_(status_bubble),
- status_view_(status_view),
- expansion_start_(0),
- expansion_end_(0) {
- }
-
- // Manage the expansion of the bubble.
- void StartExpansion(string16 expanded_text, int current_width,
- int expansion_end);
-
- // Set width of fully expanded bubble.
- void SetExpandedWidth(int expanded_width);
-
- private:
- // Animation functions.
- int GetCurrentBubbleWidth();
- void SetBubbleWidth(int width);
- void AnimateToState(double state);
- void AnimationEnded(const Animation* animation);
-
- // Manager that owns us.
- StatusBubbleViews* status_bubble_;
-
- // Change the bounds and text of this view.
- StatusView* status_view_;
-
- // Text elided (if needed) to fit maximum status bar width.
- string16 expanded_text_;
-
- // Widths at expansion start and end.
- int expansion_start_;
- int expansion_end_;
-};
-
-void StatusBubbleViews::StatusViewExpander::AnimateToState(double state) {
- SetBubbleWidth(GetCurrentBubbleWidth());
-}
-
-void StatusBubbleViews::StatusViewExpander::AnimationEnded(
- const Animation* animation) {
- SetBubbleWidth(expansion_end_);
- status_view_->SetText(expanded_text_, false);
-}
-
-void StatusBubbleViews::StatusViewExpander::StartExpansion(
- string16 expanded_text, int expansion_start,
- int expansion_end) {
- expanded_text_ = expanded_text;
- expansion_start_ = expansion_start;
- expansion_end_ = expansion_end;
- int min_duration = std::max(kMinExpansionStepDurationMS,
- static_cast<int>(kMaxExpansionStepDurationMS *
- (expansion_end - expansion_start) / 100.0));
- SetDuration(std::min(kMaxExpansionStepDurationMS, min_duration));
- Start();
-}
-
-int StatusBubbleViews::StatusViewExpander::GetCurrentBubbleWidth() {
- return static_cast<int>(expansion_start_ +
- (expansion_end_ - expansion_start_) * LinearAnimation::GetCurrentValue());
-}
-
-void StatusBubbleViews::StatusViewExpander::SetBubbleWidth(int width) {
- status_bubble_->SetBubbleWidth(width);
- status_view_->SchedulePaint();
-}
-
-// StatusBubble ---------------------------------------------------------------
-
-const int StatusBubbleViews::kShadowThickness = 1;
-
-StatusBubbleViews::StatusBubbleViews(views::View* base_view)
- : offset_(0),
- popup_(NULL),
- opacity_(0),
- base_view_(base_view),
- view_(NULL),
- download_shelf_is_visible_(false),
- is_expanded_(false),
- ALLOW_THIS_IN_INITIALIZER_LIST(expand_timer_factory_(this)) {
- expand_view_.reset();
-}
-
-StatusBubbleViews::~StatusBubbleViews() {
- CancelExpandTimer();
- if (popup_.get())
- popup_->CloseNow();
-}
-
-void StatusBubbleViews::Init() {
- if (!popup_.get()) {
- popup_.reset(Widget::CreatePopupWidget(Widget::Transparent,
- Widget::NotAcceptEvents,
- Widget::NotDeleteOnDestroy,
- Widget::MirrorOriginInRTL));
- views::Widget* frame = base_view_->GetWidget();
- if (!view_)
- view_ = new StatusView(this, popup_.get(), frame->GetThemeProvider());
- if (!expand_view_.get())
- expand_view_.reset(new StatusViewExpander(this, view_));
- popup_->SetOpacity(0x00);
- popup_->Init(frame->GetNativeView(), gfx::Rect());
- popup_->SetContentsView(view_);
- Reposition();
- popup_->Show();
- }
-}
-
-void StatusBubbleViews::Reposition() {
- if (popup_.get()) {
- gfx::Point top_left;
- views::View::ConvertPointToScreen(base_view_, &top_left);
-
- popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(),
- top_left.y() + position_.y(),
- size_.width(), size_.height()));
- }
-}
-
-gfx::Size StatusBubbleViews::GetPreferredSize() {
- return gfx::Size(0, ResourceBundle::GetSharedInstance().GetFont(
- ResourceBundle::BaseFont).GetHeight() + kTotalVerticalPadding);
-}
-
-void StatusBubbleViews::SetBounds(int x, int y, int w, int h) {
- original_position_.SetPoint(x, y);
- position_.SetPoint(base_view_->MirroredXWithWidthInsideView(x, w), y);
- size_.SetSize(w, h);
- Reposition();
-}
-
-void StatusBubbleViews::SetStatus(const string16& status_text) {
- if (size_.IsEmpty())
- return; // We have no bounds, don't attempt to show the popup.
-
- if (status_text_ == status_text && !status_text.empty())
- return;
-
- if (!IsFrameVisible())
- return; // Don't show anything if the parent isn't visible.
-
- Init();
- status_text_ = status_text;
- if (!status_text_.empty()) {
- view_->SetText(status_text, true);
- view_->Show();
- } else if (!url_text_.empty()) {
- view_->SetText(url_text_, true);
- } else {
- view_->SetText(string16(), true);
- }
-}
-
-void StatusBubbleViews::SetURL(const GURL& url, const string16& languages) {
- languages_ = languages;
- url_ = url;
- if (size_.IsEmpty())
- return; // We have no bounds, don't attempt to show the popup.
-
- Init();
-
- // If we want to clear a displayed URL but there is a status still to
- // display, display that status instead.
- if (url.is_empty() && !status_text_.empty()) {
- url_text_ = string16();
- if (IsFrameVisible())
- view_->SetText(status_text_, true);
- return;
- }
-
- // Reset expansion state only when bubble is completely hidden.
- if (view_->GetState() == StatusView::BUBBLE_HIDDEN) {
- is_expanded_ = false;
- SetBubbleWidth(GetStandardStatusBubbleWidth());
- }
-
- // Set Elided Text corresponding to the GURL object.
- gfx::Rect popup_bounds;
- popup_->GetBounds(&popup_bounds, true);
- int text_width = static_cast<int>(popup_bounds.width() -
- (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding - 1);
- url_text_ = gfx::ElideUrl(url, view_->Label::font(),
- text_width, UTF16ToWideHack(languages));
-
- std::wstring original_url_text =
- UTF16ToWideHack(net::FormatUrl(url, UTF16ToUTF8(languages)));
-
- // An URL is always treated as a left-to-right string. On right-to-left UIs
- // we need to explicitly mark the URL as LTR to make sure it is displayed
- // correctly.
- url_text_ = base::i18n::GetDisplayStringInLTRDirectionality(url_text_);
-
- if (IsFrameVisible()) {
- view_->SetText(url_text_, true);
-
- CancelExpandTimer();
-
- // If bubble is already in expanded state, shift to adjust to new text
- // size (shrinking or expanding). Otherwise delay.
- if (is_expanded_ && !url.is_empty())
- ExpandBubble();
- else if (original_url_text.length() > url_text_.length())
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- expand_timer_factory_.NewRunnableMethod(
- &StatusBubbleViews::ExpandBubble), kExpandHoverDelay);
- }
-}
-
-void StatusBubbleViews::Hide() {
- status_text_ = string16();
- url_text_ = string16();
- if (view_)
- view_->Hide();
-}
-
-void StatusBubbleViews::MouseMoved(const gfx::Point& location,
- bool left_content) {
- if (left_content)
- return;
-
- if (view_) {
- view_->ResetTimer();
-
- if (view_->GetState() != StatusView::BUBBLE_HIDDEN &&
- view_->GetState() != StatusView::BUBBLE_HIDING_FADE &&
- view_->GetState() != StatusView::BUBBLE_HIDING_TIMER) {
- AvoidMouse(location);
- }
- }
-}
-
-void StatusBubbleViews::UpdateDownloadShelfVisibility(bool visible) {
- download_shelf_is_visible_ = visible;
-}
-
-void StatusBubbleViews::AvoidMouse(const gfx::Point& location) {
- // Get the position of the frame.
- gfx::Point top_left;
- views::View::ConvertPointToScreen(base_view_, &top_left);
- // Border included.
- int window_width = base_view_->GetLocalBounds(true).width();
-
- // Get the cursor position relative to the popup.
- gfx::Point relative_location = location;
- if (base::i18n::IsRTL()) {
- int top_right_x = top_left.x() + window_width;
- relative_location.set_x(top_right_x - relative_location.x());
- } else {
- relative_location.set_x(
- relative_location.x() - (top_left.x() + position_.x()));
- }
- relative_location.set_y(
- relative_location.y() - (top_left.y() + position_.y()));
-
- // If the mouse is in a position where we think it would move the
- // status bubble, figure out where and how the bubble should be moved.
- if (relative_location.y() > -kMousePadding &&
- relative_location.x() < size_.width() + kMousePadding) {
- int offset = kMousePadding + relative_location.y();
-
- // Make the movement non-linear.
- offset = offset * offset / kMousePadding;
-
- // When the mouse is entering from the right, we want the offset to be
- // scaled by how horizontally far away the cursor is from the bubble.
- if (relative_location.x() > size_.width()) {
- offset = static_cast<int>(static_cast<float>(offset) * (
- static_cast<float>(kMousePadding -
- (relative_location.x() - size_.width())) /
- static_cast<float>(kMousePadding)));
- }
-
- // Cap the offset and change the visual presentation of the bubble
- // depending on where it ends up (so that rounded corners square off
- // and mate to the edges of the tab content).
- if (offset >= size_.height() - kShadowThickness * 2) {
- offset = size_.height() - kShadowThickness * 2;
- view_->SetStyle(StatusView::STYLE_BOTTOM);
- } else if (offset > kBubbleCornerRadius / 2 - kShadowThickness) {
- view_->SetStyle(StatusView::STYLE_FLOATING);
- } else {
- view_->SetStyle(StatusView::STYLE_STANDARD);
- }
-
- // Check if the bubble sticks out from the monitor or will obscure
- // download shelf.
- gfx::NativeView widget = base_view_->GetWidget()->GetNativeView();
- gfx::Rect monitor_rect =
- views::Screen::GetMonitorWorkAreaNearestWindow(widget);
- const int bubble_bottom_y = top_left.y() + position_.y() + size_.height();
-
- if (bubble_bottom_y + offset > monitor_rect.height() ||
- (download_shelf_is_visible_ &&
- (view_->GetStyle() == StatusView::STYLE_FLOATING ||
- view_->GetStyle() == StatusView::STYLE_BOTTOM))) {
- // The offset is still too large. Move the bubble to the right and reset
- // Y offset_ to zero.
- view_->SetStyle(StatusView::STYLE_STANDARD_RIGHT);
- offset_ = 0;
-
- // Subtract border width + bubble width.
- int right_position_x = window_width - (position_.x() + size_.width());
- popup_->SetBounds(gfx::Rect(top_left.x() + right_position_x,
- top_left.y() + position_.y(),
- size_.width(), size_.height()));
- } else {
- offset_ = offset;
- popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(),
- top_left.y() + position_.y() + offset_,
- size_.width(), size_.height()));
- }
- } else if (offset_ != 0 ||
- view_->GetStyle() == StatusView::STYLE_STANDARD_RIGHT) {
- offset_ = 0;
- view_->SetStyle(StatusView::STYLE_STANDARD);
- popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(),
- top_left.y() + position_.y(),
- size_.width(), size_.height()));
- }
-}
-
-bool StatusBubbleViews::IsFrameVisible() {
- views::Widget* frame = base_view_->GetWidget();
- if (!frame->IsVisible())
- return false;
-
- views::Window* window = frame->GetWindow();
- return !window || !window->IsMinimized();
-}
-
-void StatusBubbleViews::ExpandBubble() {
- // Elide URL to maximum possible size, then check actual length (it may
- // still be too long to fit) before expanding bubble.
- gfx::Rect popup_bounds;
- popup_->GetBounds(&popup_bounds, true);
- int max_status_bubble_width = GetMaxStatusBubbleWidth();
- url_text_ = gfx::ElideUrl(url_, view_->Label::font(),
- max_status_bubble_width, UTF16ToWideHack(languages_));
- int expanded_bubble_width =std::max(GetStandardStatusBubbleWidth(),
- std::min(view_->Label::font().GetStringWidth(UTF16ToWide(url_text_)) +
- (kShadowThickness * 2) + kTextPositionX +
- kTextHorizPadding + 1,
- max_status_bubble_width));
- is_expanded_ = true;
- expand_view_->StartExpansion(url_text_, popup_bounds.width(),
- expanded_bubble_width);
-}
-
-int StatusBubbleViews::GetStandardStatusBubbleWidth() {
- return base_view_->bounds().width() / 3;
-}
-
-int StatusBubbleViews::GetMaxStatusBubbleWidth() {
- return static_cast<int>(std::max(0, base_view_->bounds().width() -
- (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding - 1 -
- views::NativeScrollBar::GetVerticalScrollBarWidth()));
-}
-
-void StatusBubbleViews::SetBubbleWidth(int width) {
- size_.set_width(width);
- SetBounds(original_position_.x(), original_position_.y(),
- size_.width(), size_.height());
-}
-
-void StatusBubbleViews::CancelExpandTimer() {
- if (!expand_timer_factory_.empty())
- expand_timer_factory_.RevokeAll();
-}