status_bubble_views.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/status_bubble_views.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/rtl.h" 119ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/themes/theme_properties.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/theme_resources.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkPaint.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkPath.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkRect.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h" 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/theme_provider.h" 23d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/animation_delegate.h" 24d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/linear_animation.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/point.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/screen.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/skia_util.h" 2958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/gfx/text_elider.h" 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/native_theme/native_theme.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/label.h" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/scrollbar/native_scroll_bar.h" 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/root_view.h" 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h" 357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h" 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_ASH) 3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ash/wm/window_settings.h" 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The alpha and color of the bubble's shadow. 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const SkColor kShadowColor = SkColorSetARGB(30, 0, 0, 0); 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The roundedness of the edges of our bubble. 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kBubbleCornerRadius = 4; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How close the mouse can get to the infobubble before it starts sliding 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// off-screen. 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMousePadding = 20; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The horizontal offset of the text within the status bubble, not including the 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// outer shadow ring. 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kTextPositionX = 3; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The minimum horizontal space between the (right) end of the text and the edge 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of the status bubble, not including the outer shadow ring. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kTextHorizPadding = 1; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Delays before we start hiding or showing the bubble after we receive a 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// show or hide request. 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kShowDelay = 80; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kHideDelay = 250; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How long each fade should last for. 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kShowFadeDurationMS = 120; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kHideFadeDurationMS = 200; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kFramerate = 25; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How long each expansion step should take. 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMinExpansionStepDurationMS = 20; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMaxExpansionStepDurationMS = 150; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// View ----------------------------------------------------------------------- 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// StatusView manages the display of the bubble, applying text changes and 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// fading in or out the bubble as required. 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class StatusBubbleViews::StatusView : public views::Label, 77d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) public gfx::LinearAnimation, 78d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) public gfx::AnimationDelegate { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StatusView(StatusBubble* status_bubble, 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::Widget* popup, 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::ThemeProvider* theme_provider) 83d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) : gfx::LinearAnimation(kFramerate, this), 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stage_(BUBBLE_HIDDEN), 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) style_(STYLE_STANDARD), 86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) timer_factory_(this), 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_bubble_(status_bubble), 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_(popup), 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) opacity_start_(0), 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) opacity_end_(0), 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) theme_service_(theme_provider) { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetFont(rb.GetFont(ui::ResourceBundle::BaseFont)); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~StatusView() { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Remove ourself as a delegate so that we don't get notified when 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // animations end as a result of destruction. 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_delegate(NULL); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Stop(); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelTimer(); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The bubble can be in one of many stages: 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum BubbleStage { 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BUBBLE_HIDDEN, // Entirely BUBBLE_HIDDEN. 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BUBBLE_HIDING_FADE, // In a fade-out transition. 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BUBBLE_HIDING_TIMER, // Waiting before a fade-out. 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BUBBLE_SHOWING_TIMER, // Waiting before a fade-in. 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BUBBLE_SHOWING_FADE, // In a fade-in transition. 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BUBBLE_SHOWN // Fully visible. 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum BubbleStyle { 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) STYLE_BOTTOM, 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) STYLE_FLOATING, 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) STYLE_STANDARD, 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) STYLE_STANDARD_RIGHT 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set the bubble text to a certain value, hides the bubble if text is 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // an empty string. Trigger animation sequence to display if 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |should_animate_open|. 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SetText(const string16& text, bool should_animate_open); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BubbleStage GetState() const { return stage_; } 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SetStyle(BubbleStyle style); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BubbleStyle GetStyle() const { return style_; } 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Show the bubble instantly. 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Show(); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Hide the bubble instantly. 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Hide(); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Resets any timers we have. Typically called when the user moves a 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // mouse. 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ResetTimer(); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class InitialTimer; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Manage the timers that control the delay before a fade begins or ends. 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void StartTimer(base::TimeDelta time); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void OnTimer(); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void CancelTimer(); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void RestartTimer(base::TimeDelta delay); 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Manage the fades and starting and stopping the animations correctly. 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void StartFade(double start, double end, int duration); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void StartHiding(); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void StartShowing(); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Animation functions. 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double GetCurrentOpacity(); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SetOpacity(double opacity); 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void AnimateToState(double state) OVERRIDE; 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void AnimationEnded(const Animation* animation) OVERRIDE; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BubbleStage stage_; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BubbleStyle style_; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::WeakPtrFactory<StatusBubbleViews::StatusView> timer_factory_; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Manager, owns us. 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StatusBubble* status_bubble_; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Handle to the widget that contains us. 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::Widget* popup_; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The currently-displayed text. 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 text_; 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start and end opacities for the current transition - note that as a 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // fade-in can easily turn into a fade out, opacity_start_ is sometimes 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a value between 0 and 1. 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double opacity_start_; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double opacity_end_; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Holds the theme provider of the frame that created us. 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::ThemeProvider* theme_service_; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::SetText(const string16& text, 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool should_animate_open) { 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (text.empty()) { 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The string was empty. 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartHiding(); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We want to show the string. 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) text_ = text; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (should_animate_open) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartShowing(); 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SchedulePaint(); 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::Show() { 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Stop(); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelTimer(); 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetOpacity(1.0); 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->Show(); 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stage_ = BUBBLE_SHOWN; 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::Hide() { 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Stop(); 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelTimer(); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetOpacity(0.0); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) text_.clear(); 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->Hide(); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stage_ = BUBBLE_HIDDEN; 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::StartTimer(base::TimeDelta time) { 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (timer_factory_.HasWeakPtrs()) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timer_factory_.InvalidateWeakPtrs(); 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 224b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::MessageLoop::current()->PostDelayedTask( 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&StatusBubbleViews::StatusView::OnTimer, 227b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) timer_factory_.GetWeakPtr()), 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::OnTimer() { 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (stage_ == BUBBLE_HIDING_TIMER) { 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stage_ = BUBBLE_HIDING_FADE; 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartFade(1.0, 0.0, kHideFadeDurationMS); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (stage_ == BUBBLE_SHOWING_TIMER) { 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stage_ = BUBBLE_SHOWING_FADE; 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartFade(0.0, 1.0, kShowFadeDurationMS); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::CancelTimer() { 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (timer_factory_.HasWeakPtrs()) 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timer_factory_.InvalidateWeakPtrs(); 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::RestartTimer(base::TimeDelta delay) { 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelTimer(); 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartTimer(delay); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::ResetTimer() { 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (stage_ == BUBBLE_SHOWING_TIMER) { 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We hadn't yet begun showing anything when we received a new request 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for something to show, so we start from scratch. 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RestartTimer(base::TimeDelta::FromMilliseconds(kShowDelay)); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::StartFade(double start, 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double end, 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int duration) { 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) opacity_start_ = start; 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) opacity_end_ = end; 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This will also reset the currently-occurring animation. 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetDuration(duration); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Start(); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::StartHiding() { 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (stage_ == BUBBLE_SHOWN) { 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stage_ = BUBBLE_HIDING_TIMER; 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartTimer(base::TimeDelta::FromMilliseconds(kHideDelay)); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (stage_ == BUBBLE_SHOWING_TIMER) { 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stage_ = BUBBLE_HIDDEN; 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->Hide(); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelTimer(); 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (stage_ == BUBBLE_SHOWING_FADE) { 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stage_ = BUBBLE_HIDING_FADE; 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Figure out where we are in the current fade. 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double current_opacity = GetCurrentOpacity(); 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start a fade in the opposite direction. 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartFade(current_opacity, 0.0, 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int>(kHideFadeDurationMS * current_opacity)); 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::StartShowing() { 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (stage_ == BUBBLE_HIDDEN) { 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->Show(); 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stage_ = BUBBLE_SHOWING_TIMER; 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartTimer(base::TimeDelta::FromMilliseconds(kShowDelay)); 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (stage_ == BUBBLE_HIDING_TIMER) { 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stage_ = BUBBLE_SHOWN; 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelTimer(); 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (stage_ == BUBBLE_HIDING_FADE) { 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We're partway through a fade. 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stage_ = BUBBLE_SHOWING_FADE; 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Figure out where we are in the current fade. 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double current_opacity = GetCurrentOpacity(); 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start a fade in the opposite direction. 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartFade(current_opacity, 1.0, 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int>(kShowFadeDurationMS * current_opacity)); 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (stage_ == BUBBLE_SHOWING_TIMER) { 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We hadn't yet begun showing anything when we received a new request 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for something to show, so we start from scratch. 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResetTimer(); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Animation functions. 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)double StatusBubbleViews::StatusView::GetCurrentOpacity() { 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return opacity_start_ + (opacity_end_ - opacity_start_) * 317d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) gfx::LinearAnimation::GetCurrentValue(); 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::SetOpacity(double opacity) { 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->SetOpacity(static_cast<unsigned char>(opacity * 255)); 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::AnimateToState(double state) { 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetOpacity(GetCurrentOpacity()); 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::AnimationEnded( 329d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const gfx::Animation* animation) { 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetOpacity(opacity_end_); 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (stage_ == BUBBLE_HIDING_FADE) { 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stage_ = BUBBLE_HIDDEN; 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->Hide(); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (stage_ == BUBBLE_SHOWING_FADE) { 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stage_ = BUBBLE_SHOWN; 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::SetStyle(BubbleStyle style) { 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (style_ != style) { 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) style_ = style; 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SchedulePaint(); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::OnPaint(gfx::Canvas* canvas) { 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPaint paint; 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setStyle(SkPaint::kFill_Style); 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setAntiAlias(true); 3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkColor toolbar_color = theme_service_->GetColor( 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ThemeProperties::COLOR_TOOLBAR); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setColor(toolbar_color); 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect popup_bounds = popup_->GetWindowBoundsInScreen(); 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Figure out how to round the bubble's four corners. 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkScalar rad[8]; 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Top Edges - if the bubble is in its bottom position (sticking downwards), 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // then we square the top edges. Otherwise, we square the edges based on the 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // position of the bubble within the window (the bubble is positioned in the 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // southeast corner in RTL and in the southwest corner in LTR). 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (style_ == STYLE_BOTTOM) { 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Top Left corner. 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rad[0] = 0; 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rad[1] = 0; 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Top Right corner. 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rad[2] = 0; 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rad[3] = 0; 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base::i18n::IsRTL() != (style_ == STYLE_STANDARD_RIGHT)) { 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The text is RtL or the bubble is on the right side (but not both). 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Top Left corner. 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rad[0] = SkIntToScalar(kBubbleCornerRadius); 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rad[1] = SkIntToScalar(kBubbleCornerRadius); 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Top Right corner. 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rad[2] = 0; 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rad[3] = 0; 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Top Left corner. 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rad[0] = 0; 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rad[1] = 0; 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Top Right corner. 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rad[2] = SkIntToScalar(kBubbleCornerRadius); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rad[3] = SkIntToScalar(kBubbleCornerRadius); 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Bottom edges - square these off if the bubble is in its standard position 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (sticking upward). 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (style_ == STYLE_STANDARD || style_ == STYLE_STANDARD_RIGHT) { 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Bottom Right Corner. 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rad[4] = 0; 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rad[5] = 0; 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Bottom Left Corner. 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rad[6] = 0; 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rad[7] = 0; 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Bottom Right Corner. 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rad[4] = SkIntToScalar(kBubbleCornerRadius); 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rad[5] = SkIntToScalar(kBubbleCornerRadius); 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Bottom Left Corner. 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rad[6] = SkIntToScalar(kBubbleCornerRadius); 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rad[7] = SkIntToScalar(kBubbleCornerRadius); 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Draw the bubble's shadow. 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int width = popup_bounds.width(); 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int height = popup_bounds.height(); 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkRect rect(gfx::RectToSkRect(gfx::Rect(popup_bounds.size()))); 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPath shadow_path; 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) shadow_path.addRoundRect(rect, rad, SkPath::kCW_Direction); 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPaint shadow_paint; 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) shadow_paint.setAntiAlias(true); 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) shadow_paint.setColor(kShadowColor); 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawPath(shadow_path, shadow_paint); 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Draw the bubble. 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rect.set(SkIntToScalar(kShadowThickness), 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkIntToScalar(kShadowThickness), 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkIntToScalar(width - kShadowThickness), 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkIntToScalar(height - kShadowThickness)); 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPath path; 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path.addRoundRect(rect, rad, SkPath::kCW_Direction); 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawPath(path, paint); 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Draw highlight text and then the text body. In order to make sure the text 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is aligned to the right on RTL UIs, we mirror the text bounds if the 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // locale is RTL. 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int text_width = std::min( 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::Label::font().GetStringWidth(text_), 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) width - (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding); 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int text_height = height - (kShadowThickness * 2); 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect body_bounds(kShadowThickness + kTextPositionX, 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kShadowThickness, 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::max(0, text_width), 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::max(0, text_height)); 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) body_bounds.set_x(GetMirroredXForRect(body_bounds)); 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkColor text_color = 4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) theme_service_->GetColor(ThemeProperties::COLOR_TAB_TEXT); 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // DrawStringInt doesn't handle alpha, so we'll do the blending ourselves. 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) text_color = SkColorSetARGB( 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkColorGetA(text_color), 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (SkColorGetR(text_color) + SkColorGetR(toolbar_color)) / 2, 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (SkColorGetG(text_color) + SkColorGetR(toolbar_color)) / 2, 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (SkColorGetB(text_color) + SkColorGetR(toolbar_color)) / 2); 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawStringInt(text_, 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::Label::font(), 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) text_color, 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) body_bounds.x(), 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) body_bounds.y(), 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) body_bounds.width(), 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) body_bounds.height()); 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// StatusViewExpander --------------------------------------------------------- 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Manages the expansion and contraction of the status bubble as it accommodates 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// URLs too long to fit in the standard bubble. Changes are passed through the 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// StatusView to paint. 468d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)class StatusBubbleViews::StatusViewExpander : public gfx::LinearAnimation, 469d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) public gfx::AnimationDelegate { 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StatusViewExpander(StatusBubbleViews* status_bubble, 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StatusView* status_view) 473d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) : gfx::LinearAnimation(kFramerate, this), 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_bubble_(status_bubble), 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_view_(status_view), 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expansion_start_(0), 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expansion_end_(0) { 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Manage the expansion of the bubble. 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void StartExpansion(const string16& expanded_text, 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int current_width, 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int expansion_end); 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set width of fully expanded bubble. 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SetExpandedWidth(int expanded_width); 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Animation functions. 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int GetCurrentBubbleWidth(); 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SetBubbleWidth(int width); 4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void AnimateToState(double state) OVERRIDE; 493d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE; 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Manager that owns us. 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StatusBubbleViews* status_bubble_; 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Change the bounds and text of this view. 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StatusView* status_view_; 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Text elided (if needed) to fit maximum status bar width. 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 expanded_text_; 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Widths at expansion start and end. 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int expansion_start_; 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int expansion_end_; 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusViewExpander::AnimateToState(double state) { 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetBubbleWidth(GetCurrentBubbleWidth()); 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusViewExpander::AnimationEnded( 514d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const gfx::Animation* animation) { 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetBubbleWidth(expansion_end_); 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_view_->SetText(expanded_text_, false); 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusViewExpander::StartExpansion( 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& expanded_text, 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int expansion_start, 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int expansion_end) { 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expanded_text_ = expanded_text; 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expansion_start_ = expansion_start; 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expansion_end_ = expansion_end; 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int min_duration = std::max(kMinExpansionStepDurationMS, 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int>(kMaxExpansionStepDurationMS * 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (expansion_end - expansion_start) / 100.0)); 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetDuration(std::min(kMaxExpansionStepDurationMS, min_duration)); 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Start(); 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatusBubbleViews::StatusViewExpander::GetCurrentBubbleWidth() { 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return static_cast<int>(expansion_start_ + 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (expansion_end_ - expansion_start_) * 536d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) gfx::LinearAnimation::GetCurrentValue()); 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusViewExpander::SetBubbleWidth(int width) { 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_bubble_->SetBubbleWidth(width); 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_view_->SchedulePaint(); 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// StatusBubble --------------------------------------------------------------- 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int StatusBubbleViews::kShadowThickness = 1; 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StatusBubbleViews::StatusBubbleViews(views::View* base_view) 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : contains_mouse_(false), 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset_(0), 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) opacity_(0), 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base_view_(base_view), 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_(NULL), 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_shelf_is_visible_(false), 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_expanded_(false), 556c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) expand_timer_factory_(this) { 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expand_view_.reset(); 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StatusBubbleViews::~StatusBubbleViews() { 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelExpandTimer(); 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (popup_.get()) 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->CloseNow(); 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::Init() { 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!popup_.get()) { 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_.reset(new views::Widget); 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::Widget* frame = base_view_->GetWidget(); 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!view_) 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_ = new StatusView(this, popup_.get(), frame->GetThemeProvider()); 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!expand_view_.get()) 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expand_view_.reset(new StatusViewExpander(this, view_)); 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); 575eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.accept_events = false; 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) params.parent = frame->GetNativeView(); 5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) params.context = frame->GetNativeView(); 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->Init(params); 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We do our own animation and don't want any from the system. 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->SetVisibilityChangedAnimationsEnabled(false); 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->SetOpacity(0x00); 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->SetContentsView(view_); 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_ASH) 58658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ash::wm::GetWindowSettings(popup_->GetNativeWindow())-> 58758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) set_ignored_by_shelf(true); 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Reposition(); 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::Reposition() { 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (popup_.get()) { 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point top_left; 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::View::ConvertPointToScreen(base_view_, &top_left); 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(), 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) top_left.y() + position_.y(), 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_.width(), size_.height())); 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Size StatusBubbleViews::GetPreferredSize() { 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gfx::Size(0, ui::ResourceBundle::GetSharedInstance().GetFont( 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::ResourceBundle::BaseFont).GetHeight() + kTotalVerticalPadding); 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::SetBounds(int x, int y, int w, int h) { 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) original_position_.SetPoint(x, y); 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) position_.SetPoint(base_view_->GetMirroredXWithWidthInView(x, w), y); 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_.SetSize(w, h); 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Reposition(); 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (popup_.get() && contains_mouse_) 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AvoidMouse(last_mouse_moved_location_); 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::SetStatus(const string16& status_text) { 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (size_.IsEmpty()) 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // We have no bounds, don't attempt to show the popup. 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (status_text_ == status_text && !status_text.empty()) 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsFrameVisible()) 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // Don't show anything if the parent isn't visible. 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(); 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_text_ = status_text; 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!status_text_.empty()) { 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->SetText(status_text, true); 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->Show(); 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!url_text_.empty()) { 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->SetText(url_text_, true); 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->SetText(string16(), true); 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::SetURL(const GURL& url, const std::string& languages) { 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_ = url; 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) languages_ = languages; 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (size_.IsEmpty()) 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // We have no bounds, don't attempt to show the popup. 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(); 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we want to clear a displayed URL but there is a status still to 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // display, display that status instead. 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (url.is_empty() && !status_text_.empty()) { 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_text_ = string16(); 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsFrameVisible()) 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->SetText(status_text_, true); 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Reset expansion state only when bubble is completely hidden. 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (view_->GetState() == StatusView::BUBBLE_HIDDEN) { 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_expanded_ = false; 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetBubbleWidth(GetStandardStatusBubbleWidth()); 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set Elided Text corresponding to the GURL object. 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect popup_bounds = popup_->GetWindowBoundsInScreen(); 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int text_width = static_cast<int>(popup_bounds.width() - 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding - 1); 66758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) url_text_ = gfx::ElideUrl(url, view_->Label::font(), text_width, languages); 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // An URL is always treated as a left-to-right string. On right-to-left UIs 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we need to explicitly mark the URL as LTR to make sure it is displayed 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // correctly. 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_text_ = base::i18n::GetDisplayStringInLTRDirectionality(url_text_); 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsFrameVisible()) { 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->SetText(url_text_, true); 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelExpandTimer(); 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If bubble is already in expanded state, shift to adjust to new text 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // size (shrinking or expanding). Otherwise delay. 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_expanded_ && !url.is_empty()) { 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExpandBubble(); 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (net::FormatUrl(url, languages).length() > url_text_.length()) { 684b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::MessageLoop::current()->PostDelayedTask( 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&StatusBubbleViews::ExpandBubble, 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expand_timer_factory_.GetWeakPtr()), 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeDelta::FromMilliseconds(kExpandHoverDelay)); 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::Hide() { 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_text_ = string16(); 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_text_ = string16(); 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (view_) 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->Hide(); 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::MouseMoved(const gfx::Point& location, 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool left_content) { 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contains_mouse_ = !left_content; 7037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (left_content) { 7047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch Reposition(); 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 7067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_mouse_moved_location_ = location; 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (view_) { 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->ResetTimer(); 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (view_->GetState() != StatusView::BUBBLE_HIDDEN && 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->GetState() != StatusView::BUBBLE_HIDING_FADE && 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->GetState() != StatusView::BUBBLE_HIDING_TIMER) { 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AvoidMouse(location); 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::UpdateDownloadShelfVisibility(bool visible) { 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_shelf_is_visible_ = visible; 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::AvoidMouse(const gfx::Point& location) { 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the position of the frame. 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point top_left; 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::View::ConvertPointToScreen(base_view_, &top_left); 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Border included. 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int window_width = base_view_->GetLocalBounds().width(); 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the cursor position relative to the popup. 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point relative_location = location; 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base::i18n::IsRTL()) { 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int top_right_x = top_left.x() + window_width; 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) relative_location.set_x(top_right_x - relative_location.x()); 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) relative_location.set_x( 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) relative_location.x() - (top_left.x() + position_.x())); 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) relative_location.set_y( 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) relative_location.y() - (top_left.y() + position_.y())); 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the mouse is in a position where we think it would move the 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // status bubble, figure out where and how the bubble should be moved. 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (relative_location.y() > -kMousePadding && 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) relative_location.x() < size_.width() + kMousePadding) { 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int offset = kMousePadding + relative_location.y(); 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make the movement non-linear. 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset = offset * offset / kMousePadding; 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When the mouse is entering from the right, we want the offset to be 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // scaled by how horizontally far away the cursor is from the bubble. 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (relative_location.x() > size_.width()) { 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset = static_cast<int>(static_cast<float>(offset) * ( 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<float>(kMousePadding - 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (relative_location.x() - size_.width())) / 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<float>(kMousePadding))); 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cap the offset and change the visual presentation of the bubble 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // depending on where it ends up (so that rounded corners square off 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and mate to the edges of the tab content). 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (offset >= size_.height() - kShadowThickness * 2) { 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset = size_.height() - kShadowThickness * 2; 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->SetStyle(StatusView::STYLE_BOTTOM); 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (offset > kBubbleCornerRadius / 2 - kShadowThickness) { 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->SetStyle(StatusView::STYLE_FLOATING); 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->SetStyle(StatusView::STYLE_STANDARD); 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if the bubble sticks out from the monitor or will obscure 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // download shelf. 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::NativeView window = base_view_->GetWidget()->GetNativeView(); 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect monitor_rect = gfx::Screen::GetScreenFor(window)-> 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetDisplayNearestWindow(window).work_area(); 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int bubble_bottom_y = top_left.y() + position_.y() + size_.height(); 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (bubble_bottom_y + offset > monitor_rect.height() || 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (download_shelf_is_visible_ && 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (view_->GetStyle() == StatusView::STYLE_FLOATING || 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->GetStyle() == StatusView::STYLE_BOTTOM))) { 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The offset is still too large. Move the bubble to the right and reset 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Y offset_ to zero. 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->SetStyle(StatusView::STYLE_STANDARD_RIGHT); 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset_ = 0; 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Subtract border width + bubble width. 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int right_position_x = window_width - (position_.x() + size_.width()); 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->SetBounds(gfx::Rect(top_left.x() + right_position_x, 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) top_left.y() + position_.y(), 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_.width(), size_.height())); 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset_ = offset; 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(), 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) top_left.y() + position_.y() + offset_, 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_.width(), size_.height())); 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (offset_ != 0 || 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->GetStyle() == StatusView::STYLE_STANDARD_RIGHT) { 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset_ = 0; 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->SetStyle(StatusView::STYLE_STANDARD); 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(), 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) top_left.y() + position_.y(), 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_.width(), size_.height())); 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool StatusBubbleViews::IsFrameVisible() { 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::Widget* frame = base_view_->GetWidget(); 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!frame->IsVisible()) 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::Widget* window = frame->GetTopLevelWidget(); 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !window || !window->IsMinimized(); 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::ExpandBubble() { 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Elide URL to maximum possible size, then check actual length (it may 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // still be too long to fit) before expanding bubble. 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect popup_bounds = popup_->GetWindowBoundsInScreen(); 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_status_bubble_width = GetMaxStatusBubbleWidth(); 82458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) url_text_ = gfx::ElideUrl(url_, view_->Label::font(), 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_status_bubble_width, languages_); 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int expanded_bubble_width =std::max(GetStandardStatusBubbleWidth(), 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::min(view_->Label::font().GetStringWidth(url_text_) + 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (kShadowThickness * 2) + kTextPositionX + 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kTextHorizPadding + 1, 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_status_bubble_width)); 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_expanded_ = true; 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expand_view_->StartExpansion(url_text_, popup_bounds.width(), 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expanded_bubble_width); 8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatusBubbleViews::GetStandardStatusBubbleWidth() { 8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return base_view_->bounds().width() / 3; 8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatusBubbleViews::GetMaxStatusBubbleWidth() { 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ui::NativeTheme* theme = base_view_->GetNativeTheme(); 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return static_cast<int>(std::max(0, base_view_->bounds().width() - 8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding - 1 - 8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::NativeScrollBar::GetVerticalScrollBarWidth(theme))); 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::SetBubbleWidth(int width) { 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_.set_width(width); 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetBounds(original_position_.x(), original_position_.y(), 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_.width(), size_.height()); 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::CancelExpandTimer() { 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (expand_timer_factory_.HasWeakPtrs()) 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expand_timer_factory_.InvalidateWeakPtrs(); 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 857