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