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) 9f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ash/wm/window_state.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/rtl.h" 129ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h" 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/themes/theme_properties.h" 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/ui/elide_url.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/SkRect.h" 205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/aura/window.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/theme_provider.h" 22d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/animation_delegate.h" 23d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/linear_animation.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h" 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/gfx/font_list.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/point.h" 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/gfx/rect.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/screen.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/skia_util.h" 3058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/gfx/text_elider.h" 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/gfx/text_utils.h" 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/native_theme/native_theme.h" 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/scrollbar/native_scroll_bar.h" 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/root_view.h" 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h" 367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h" 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The alpha and color of the bubble's shadow. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const SkColor kShadowColor = SkColorSetARGB(30, 0, 0, 0); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The roundedness of the edges of our bubble. 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kBubbleCornerRadius = 4; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How close the mouse can get to the infobubble before it starts sliding 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// off-screen. 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMousePadding = 20; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The horizontal offset of the text within the status bubble, not including the 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// outer shadow ring. 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kTextPositionX = 3; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The minimum horizontal space between the (right) end of the text and the edge 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of the status bubble, not including the outer shadow ring. 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kTextHorizPadding = 1; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Delays before we start hiding or showing the bubble after we receive a 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// show or hide request. 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kShowDelay = 80; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kHideDelay = 250; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How long each fade should last for. 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kShowFadeDurationMS = 120; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kHideFadeDurationMS = 200; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kFramerate = 25; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// How long each expansion step should take. 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMinExpansionStepDurationMS = 20; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMaxExpansionStepDurationMS = 150; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// StatusBubbleViews::StatusViewAnimation -------------------------------------- 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class StatusBubbleViews::StatusViewAnimation : public gfx::LinearAnimation, 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public gfx::AnimationDelegate { 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) StatusViewAnimation(StatusView* status_view, 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) double opacity_start, 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) double opacity_end); 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) virtual ~StatusViewAnimation(); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) double GetCurrentOpacity(); 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private: 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // gfx::LinearAnimation: 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) virtual void AnimateToState(double state) OVERRIDE; 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // gfx::AnimationDelegate: 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) virtual void AnimationEnded(const Animation* animation) OVERRIDE; 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) StatusView* status_view_; 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Start and end opacities for the current transition - note that as a 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // fade-in can easily turn into a fade out, opacity_start_ is sometimes 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // a value between 0 and 1. 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) double opacity_start_; 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) double opacity_end_; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(StatusViewAnimation); 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}; 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// StatusBubbleViews::StatusView ----------------------------------------------- 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// StatusView manages the display of the bubble, applying text changes and 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// fading in or out the bubble as required. 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class StatusBubbleViews::StatusView : public views::View { 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public: 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // The bubble can be in one of many states: 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) enum BubbleState { 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BUBBLE_HIDDEN, // Entirely BUBBLE_HIDDEN. 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BUBBLE_HIDING_FADE, // In a fade-out transition. 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BUBBLE_HIDING_TIMER, // Waiting before a fade-out. 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BUBBLE_SHOWING_TIMER, // Waiting before a fade-in. 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BUBBLE_SHOWING_FADE, // In a fade-in transition. 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BUBBLE_SHOWN // Fully visible. 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum BubbleStyle { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) STYLE_BOTTOM, 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) STYLE_FLOATING, 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) STYLE_STANDARD, 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) STYLE_STANDARD_RIGHT 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch StatusView(views::Widget* popup, 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ui::ThemeProvider* theme_provider); 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) virtual ~StatusView(); 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set the bubble text to a certain value, hides the bubble if text is 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // an empty string. Trigger animation sequence to display if 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |should_animate_open|. 131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) void SetText(const base::string16& text, bool should_animate_open); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) BubbleState state() const { return state_; } 1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) BubbleStyle style() const { return style_; } 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SetStyle(BubbleStyle style); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Show the bubble instantly. 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Show(); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Hide the bubble instantly. 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Hide(); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Resets any timers we have. Typically called when the user moves a 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // mouse. 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ResetTimer(); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // This call backs the StatusView in order to fade the bubble in and out. 1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void SetOpacity(double opacity); 1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Depending on the state of the bubble this will either hide the popup or 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // not. 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void OnAnimationEnded(); 1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class InitialTimer; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Manage the timers that control the delay before a fade begins or ends. 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void StartTimer(base::TimeDelta time); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void OnTimer(); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void CancelTimer(); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void RestartTimer(base::TimeDelta delay); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Manage the fades and starting and stopping the animations correctly. 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void StartFade(double start, double end, int duration); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void StartHiding(); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void StartShowing(); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // views::View: 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) BubbleState state_; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BubbleStyle style_; 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::WeakPtrFactory<StatusBubbleViews::StatusView> timer_factory_; 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<StatusViewAnimation> animation_; 1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Handle to the widget that contains us. 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::Widget* popup_; 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The currently-displayed text. 182a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 text_; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Holds the theme provider of the frame that created us. 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::ThemeProvider* theme_service_; 1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(StatusView); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1900529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochStatusBubbleViews::StatusView::StatusView(views::Widget* popup, 1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ui::ThemeProvider* theme_provider) 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : state_(BUBBLE_HIDDEN), 1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) style_(STYLE_STANDARD), 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) timer_factory_(this), 1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) animation_(new StatusViewAnimation(this, 0, 0)), 1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) popup_(popup), 1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) theme_service_(theme_provider) { 1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)StatusBubbleViews::StatusView::~StatusView() { 2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) animation_->Stop(); 2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CancelTimer(); 2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 205a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void StatusBubbleViews::StatusView::SetText(const base::string16& text, 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool should_animate_open) { 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (text.empty()) { 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The string was empty. 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartHiding(); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We want to show the string. 212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (text != text_) { 213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) text_ = text; 214f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SchedulePaint(); 215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (should_animate_open) 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartShowing(); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::Show() { 2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) animation_->Stop(); 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelTimer(); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetOpacity(1.0); 2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) popup_->ShowInactive(); 2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) state_ = BUBBLE_SHOWN; 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::Hide() { 2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) animation_->Stop(); 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelTimer(); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetOpacity(0.0); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) text_.clear(); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->Hide(); 2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) state_ = BUBBLE_HIDDEN; 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::StartTimer(base::TimeDelta time) { 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (timer_factory_.HasWeakPtrs()) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timer_factory_.InvalidateWeakPtrs(); 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 242b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::MessageLoop::current()->PostDelayedTask( 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&StatusBubbleViews::StatusView::OnTimer, 245b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) timer_factory_.GetWeakPtr()), 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::OnTimer() { 2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (state_ == BUBBLE_HIDING_TIMER) { 2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) state_ = BUBBLE_HIDING_FADE; 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartFade(1.0, 0.0, kHideFadeDurationMS); 2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (state_ == BUBBLE_SHOWING_TIMER) { 2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) state_ = BUBBLE_SHOWING_FADE; 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartFade(0.0, 1.0, kShowFadeDurationMS); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::CancelTimer() { 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (timer_factory_.HasWeakPtrs()) 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timer_factory_.InvalidateWeakPtrs(); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::RestartTimer(base::TimeDelta delay) { 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelTimer(); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartTimer(delay); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::ResetTimer() { 2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (state_ == BUBBLE_SHOWING_TIMER) { 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We hadn't yet begun showing anything when we received a new request 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for something to show, so we start from scratch. 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RestartTimer(base::TimeDelta::FromMilliseconds(kShowDelay)); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::StartFade(double start, 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double end, 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int duration) { 2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) animation_.reset(new StatusViewAnimation(this, start, end)); 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This will also reset the currently-occurring animation. 2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) animation_->SetDuration(duration); 2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) animation_->Start(); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::StartHiding() { 2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (state_ == BUBBLE_SHOWN) { 2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) state_ = BUBBLE_HIDING_TIMER; 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartTimer(base::TimeDelta::FromMilliseconds(kHideDelay)); 2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (state_ == BUBBLE_SHOWING_TIMER) { 2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) state_ = BUBBLE_HIDDEN; 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->Hide(); 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelTimer(); 2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (state_ == BUBBLE_SHOWING_FADE) { 2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) state_ = BUBBLE_HIDING_FADE; 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Figure out where we are in the current fade. 2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) double current_opacity = animation_->GetCurrentOpacity(); 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start a fade in the opposite direction. 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartFade(current_opacity, 0.0, 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int>(kHideFadeDurationMS * current_opacity)); 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::StartShowing() { 3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (state_ == BUBBLE_HIDDEN) { 3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) popup_->ShowInactive(); 3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) state_ = BUBBLE_SHOWING_TIMER; 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartTimer(base::TimeDelta::FromMilliseconds(kShowDelay)); 3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (state_ == BUBBLE_HIDING_TIMER) { 3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) state_ = BUBBLE_SHOWN; 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelTimer(); 3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (state_ == BUBBLE_HIDING_FADE) { 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We're partway through a fade. 3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) state_ = BUBBLE_SHOWING_FADE; 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Figure out where we are in the current fade. 3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) double current_opacity = animation_->GetCurrentOpacity(); 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start a fade in the opposite direction. 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartFade(current_opacity, 1.0, 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int>(kShowFadeDurationMS * current_opacity)); 3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (state_ == BUBBLE_SHOWING_TIMER) { 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We hadn't yet begun showing anything when we received a new request 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for something to show, so we start from scratch. 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResetTimer(); 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::SetOpacity(double opacity) { 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->SetOpacity(static_cast<unsigned char>(opacity * 255)); 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::SetStyle(BubbleStyle style) { 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (style_ != style) { 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) style_ = style; 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SchedulePaint(); 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void StatusBubbleViews::StatusView::OnAnimationEnded() { 3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (state_ == BUBBLE_HIDING_FADE) { 3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) state_ = BUBBLE_HIDDEN; 3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) popup_->Hide(); 3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (state_ == BUBBLE_SHOWING_FADE) { 3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) state_ = BUBBLE_SHOWN; 3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusView::OnPaint(gfx::Canvas* canvas) { 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPaint paint; 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setStyle(SkPaint::kFill_Style); 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setAntiAlias(true); 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkColor toolbar_color = theme_service_->GetColor( 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ThemeProperties::COLOR_TOOLBAR); 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setColor(toolbar_color); 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect popup_bounds = popup_->GetWindowBoundsInScreen(); 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SkScalar rad[8] = {}; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Top Edges - if the bubble is in its bottom position (sticking downwards), 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // then we square the top edges. Otherwise, we square the edges based on the 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // position of the bubble within the window (the bubble is positioned in the 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // southeast corner in RTL and in the southwest corner in LTR). 3671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (style_ != STYLE_BOTTOM) { 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base::i18n::IsRTL() != (style_ == STYLE_STANDARD_RIGHT)) { 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The text is RtL or the bubble is on the right side (but not both). 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Top Left corner. 3721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci rad[0] = kBubbleCornerRadius; 3731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci rad[1] = kBubbleCornerRadius; 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Top Right corner. 3761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci rad[2] = kBubbleCornerRadius; 3771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci rad[3] = kBubbleCornerRadius; 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Bottom edges - Keep these squared off if the bubble is in its standard 3821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // position (sticking upward). 3831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (style_ != STYLE_STANDARD && style_ != STYLE_STANDARD_RIGHT) { 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Bottom Right Corner. 3851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci rad[4] = kBubbleCornerRadius; 3861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci rad[5] = kBubbleCornerRadius; 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Bottom Left Corner. 3891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci rad[6] = kBubbleCornerRadius; 3901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci rad[7] = kBubbleCornerRadius; 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Draw the bubble's shadow. 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int width = popup_bounds.width(); 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int height = popup_bounds.height(); 3961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci gfx::Rect rect(gfx::Rect(popup_bounds.size())); 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPaint shadow_paint; 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) shadow_paint.setAntiAlias(true); 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) shadow_paint.setColor(kShadowColor); 4001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SkRRect rrect; 4021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci rrect.setRectRadii(RectToSkRect(rect), (const SkVector*)rad); 4031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci canvas->sk_canvas()->drawRRect(rrect, paint); 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Draw the bubble. 4061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci rect.SetRect(SkIntToScalar(kShadowThickness), 4071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SkIntToScalar(kShadowThickness), 4081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SkIntToScalar(width), 4091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SkIntToScalar(height)); 4101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci rrect.setRectRadii(RectToSkRect(rect), (const SkVector*)rad); 4111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci canvas->sk_canvas()->drawRRect(rrect, paint); 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Draw highlight text and then the text body. In order to make sure the text 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is aligned to the right on RTL UIs, we mirror the text bounds if the 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // locale is RTL. 4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const gfx::FontList font_list; 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int text_width = std::min( 4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) gfx::GetStringWidth(text_, font_list), 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) width - (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding); 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int text_height = height - (kShadowThickness * 2); 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect body_bounds(kShadowThickness + kTextPositionX, 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kShadowThickness, 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::max(0, text_width), 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::max(0, text_height)); 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) body_bounds.set_x(GetMirroredXForRect(body_bounds)); 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkColor text_color = 427f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) theme_service_->GetColor(ThemeProperties::COLOR_STATUS_BAR_TEXT); 4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) canvas->DrawStringRect(text_, font_list, text_color, body_bounds); 4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// StatusBubbleViews::StatusViewAnimation -------------------------------------- 4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)StatusBubbleViews::StatusViewAnimation::StatusViewAnimation( 4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) StatusView* status_view, 4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) double opacity_start, 4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) double opacity_end) 4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : gfx::LinearAnimation(kFramerate, this), 4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) status_view_(status_view), 4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) opacity_start_(opacity_start), 4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) opacity_end_(opacity_end) { 4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)StatusBubbleViews::StatusViewAnimation::~StatusViewAnimation() { 4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Remove ourself as a delegate so that we don't get notified when 4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // animations end as a result of destruction. 4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) set_delegate(NULL); 4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)double StatusBubbleViews::StatusViewAnimation::GetCurrentOpacity() { 4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return opacity_start_ + (opacity_end_ - opacity_start_) * 4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) gfx::LinearAnimation::GetCurrentValue(); 4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void StatusBubbleViews::StatusViewAnimation::AnimateToState(double state) { 4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) status_view_->SetOpacity(GetCurrentOpacity()); 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void StatusBubbleViews::StatusViewAnimation::AnimationEnded( 4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const gfx::Animation* animation) { 4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) status_view_->SetOpacity(opacity_end_); 4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) status_view_->OnAnimationEnded(); 4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// StatusBubbleViews::StatusViewExpander --------------------------------------- 4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Manages the expansion and contraction of the status bubble as it accommodates 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// URLs too long to fit in the standard bubble. Changes are passed through the 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// StatusView to paint. 470d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)class StatusBubbleViews::StatusViewExpander : public gfx::LinearAnimation, 471d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) public gfx::AnimationDelegate { 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StatusViewExpander(StatusBubbleViews* status_bubble, 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StatusView* status_view) 475d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) : gfx::LinearAnimation(kFramerate, this), 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_bubble_(status_bubble), 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_view_(status_view), 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expansion_start_(0), 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expansion_end_(0) { 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Manage the expansion of the bubble. 483a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) void StartExpansion(const base::string16& expanded_text, 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int current_width, 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int expansion_end); 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set width of fully expanded bubble. 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SetExpandedWidth(int expanded_width); 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Animation functions. 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int GetCurrentBubbleWidth(); 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SetBubbleWidth(int width); 4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void AnimateToState(double state) OVERRIDE; 495d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE; 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Manager that owns us. 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StatusBubbleViews* status_bubble_; 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Change the bounds and text of this view. 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StatusView* status_view_; 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Text elided (if needed) to fit maximum status bar width. 504a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 expanded_text_; 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Widths at expansion start and end. 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int expansion_start_; 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int expansion_end_; 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusViewExpander::AnimateToState(double state) { 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetBubbleWidth(GetCurrentBubbleWidth()); 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusViewExpander::AnimationEnded( 516d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const gfx::Animation* animation) { 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetBubbleWidth(expansion_end_); 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_view_->SetText(expanded_text_, false); 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusViewExpander::StartExpansion( 522a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& expanded_text, 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int expansion_start, 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int expansion_end) { 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expanded_text_ = expanded_text; 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expansion_start_ = expansion_start; 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expansion_end_ = expansion_end; 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int min_duration = std::max(kMinExpansionStepDurationMS, 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int>(kMaxExpansionStepDurationMS * 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (expansion_end - expansion_start) / 100.0)); 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetDuration(std::min(kMaxExpansionStepDurationMS, min_duration)); 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Start(); 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatusBubbleViews::StatusViewExpander::GetCurrentBubbleWidth() { 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return static_cast<int>(expansion_start_ + 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (expansion_end_ - expansion_start_) * 538d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) gfx::LinearAnimation::GetCurrentValue()); 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::StatusViewExpander::SetBubbleWidth(int width) { 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_bubble_->SetBubbleWidth(width); 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_view_->SchedulePaint(); 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// StatusBubbleViews ----------------------------------------------------------- 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int StatusBubbleViews::kShadowThickness = 1; 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StatusBubbleViews::StatusBubbleViews(views::View* base_view) 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : contains_mouse_(false), 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset_(0), 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base_view_(base_view), 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_(NULL), 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_shelf_is_visible_(false), 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_expanded_(false), 558c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) expand_timer_factory_(this) { 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expand_view_.reset(); 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StatusBubbleViews::~StatusBubbleViews() { 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelExpandTimer(); 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (popup_.get()) 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->CloseNow(); 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::Init() { 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!popup_.get()) { 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_.reset(new views::Widget); 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::Widget* frame = base_view_->GetWidget(); 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!view_) 5730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch view_ = new StatusView(popup_.get(), frame->GetThemeProvider()); 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!expand_view_.get()) 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expand_view_.reset(new StatusViewExpander(this, view_)); 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); 577eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.accept_events = false; 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) params.parent = frame->GetNativeView(); 581116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch params.context = frame->GetNativeWindow(); 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->Init(params); 583a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) popup_->GetNativeView()->SetName("StatusBubbleViews"); 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We do our own animation and don't want any from the system. 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->SetVisibilityChangedAnimationsEnabled(false); 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->SetOpacity(0x00); 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->SetContentsView(view_); 58868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) ash::wm::GetWindowState(popup_->GetNativeWindow())-> 58958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) set_ignored_by_shelf(true); 5905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RepositionPopup(); 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::Reposition() { 5955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // In restored mode, the client area has a client edge between it and the 5965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // frame. 5975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int overlap = kShadowThickness; 5985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int height = GetPreferredSize().height(); 5995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int base_view_height = base_view()->bounds().height(); 6005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) gfx::Point origin(-overlap, base_view_height - height + overlap); 6015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetBounds(origin.x(), origin.y(), base_view()->bounds().width() / 3, height); 6025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 6035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 6045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void StatusBubbleViews::RepositionPopup() { 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (popup_.get()) { 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point top_left; 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::View::ConvertPointToScreen(base_view_, &top_left); 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(), 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) top_left.y() + position_.y(), 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_.width(), size_.height())); 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Size StatusBubbleViews::GetPreferredSize() { 6165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return gfx::Size(0, gfx::FontList().GetHeight() + kTotalVerticalPadding); 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::SetBounds(int x, int y, int w, int h) { 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) original_position_.SetPoint(x, y); 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) position_.SetPoint(base_view_->GetMirroredXWithWidthInView(x, w), y); 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_.SetSize(w, h); 6235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RepositionPopup(); 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (popup_.get() && contains_mouse_) 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AvoidMouse(last_mouse_moved_location_); 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 628a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void StatusBubbleViews::SetStatus(const base::string16& status_text) { 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (size_.IsEmpty()) 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // We have no bounds, don't attempt to show the popup. 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (status_text_ == status_text && !status_text.empty()) 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsFrameVisible()) 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // Don't show anything if the parent isn't visible. 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(); 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_text_ = status_text; 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!status_text_.empty()) { 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->SetText(status_text, true); 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->Show(); 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!url_text_.empty()) { 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->SetText(url_text_, true); 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) view_->SetText(base::string16(), true); 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::SetURL(const GURL& url, const std::string& languages) { 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_ = url; 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) languages_ = languages; 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (size_.IsEmpty()) 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // We have no bounds, don't attempt to show the popup. 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(); 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we want to clear a displayed URL but there is a status still to 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // display, display that status instead. 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (url.is_empty() && !status_text_.empty()) { 661a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) url_text_ = base::string16(); 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsFrameVisible()) 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->SetText(status_text_, true); 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Reset expansion state only when bubble is completely hidden. 6685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (view_->state() == StatusView::BUBBLE_HIDDEN) { 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_expanded_ = false; 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetBubbleWidth(GetStandardStatusBubbleWidth()); 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set Elided Text corresponding to the GURL object. 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect popup_bounds = popup_->GetWindowBoundsInScreen(); 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int text_width = static_cast<int>(popup_bounds.width() - 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding - 1); 6775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) url_text_ = ElideUrl(url, gfx::FontList(), text_width, languages); 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // An URL is always treated as a left-to-right string. On right-to-left UIs 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we need to explicitly mark the URL as LTR to make sure it is displayed 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // correctly. 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_text_ = base::i18n::GetDisplayStringInLTRDirectionality(url_text_); 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsFrameVisible()) { 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->SetText(url_text_, true); 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelExpandTimer(); 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If bubble is already in expanded state, shift to adjust to new text 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // size (shrinking or expanding). Otherwise delay. 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_expanded_ && !url.is_empty()) { 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExpandBubble(); 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (net::FormatUrl(url, languages).length() > url_text_.length()) { 694b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::MessageLoop::current()->PostDelayedTask( 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&StatusBubbleViews::ExpandBubble, 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expand_timer_factory_.GetWeakPtr()), 6985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::TimeDelta::FromMilliseconds(kExpandHoverDelayMS)); 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::Hide() { 704a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) status_text_ = base::string16(); 705a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) url_text_ = base::string16(); 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (view_) 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->Hide(); 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::MouseMoved(const gfx::Point& location, 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool left_content) { 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contains_mouse_ = !left_content; 7137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (left_content) { 7145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RepositionPopup(); 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 7167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_mouse_moved_location_ = location; 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (view_) { 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->ResetTimer(); 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (view_->state() != StatusView::BUBBLE_HIDDEN && 7235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) view_->state() != StatusView::BUBBLE_HIDING_FADE && 7245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) view_->state() != StatusView::BUBBLE_HIDING_TIMER) { 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AvoidMouse(location); 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::UpdateDownloadShelfVisibility(bool visible) { 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_shelf_is_visible_ = visible; 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::AvoidMouse(const gfx::Point& location) { 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the position of the frame. 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point top_left; 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::View::ConvertPointToScreen(base_view_, &top_left); 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Border included. 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int window_width = base_view_->GetLocalBounds().width(); 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the cursor position relative to the popup. 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point relative_location = location; 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base::i18n::IsRTL()) { 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int top_right_x = top_left.x() + window_width; 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) relative_location.set_x(top_right_x - relative_location.x()); 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) relative_location.set_x( 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) relative_location.x() - (top_left.x() + position_.x())); 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) relative_location.set_y( 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) relative_location.y() - (top_left.y() + position_.y())); 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the mouse is in a position where we think it would move the 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // status bubble, figure out where and how the bubble should be moved. 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (relative_location.y() > -kMousePadding && 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) relative_location.x() < size_.width() + kMousePadding) { 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int offset = kMousePadding + relative_location.y(); 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make the movement non-linear. 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset = offset * offset / kMousePadding; 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When the mouse is entering from the right, we want the offset to be 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // scaled by how horizontally far away the cursor is from the bubble. 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (relative_location.x() > size_.width()) { 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset = static_cast<int>(static_cast<float>(offset) * ( 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<float>(kMousePadding - 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (relative_location.x() - size_.width())) / 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<float>(kMousePadding))); 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cap the offset and change the visual presentation of the bubble 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // depending on where it ends up (so that rounded corners square off 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and mate to the edges of the tab content). 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (offset >= size_.height() - kShadowThickness * 2) { 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset = size_.height() - kShadowThickness * 2; 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->SetStyle(StatusView::STYLE_BOTTOM); 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (offset > kBubbleCornerRadius / 2 - kShadowThickness) { 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->SetStyle(StatusView::STYLE_FLOATING); 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->SetStyle(StatusView::STYLE_STANDARD); 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if the bubble sticks out from the monitor or will obscure 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // download shelf. 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::NativeView window = base_view_->GetWidget()->GetNativeView(); 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect monitor_rect = gfx::Screen::GetScreenFor(window)-> 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetDisplayNearestWindow(window).work_area(); 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int bubble_bottom_y = top_left.y() + position_.y() + size_.height(); 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (bubble_bottom_y + offset > monitor_rect.height() || 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (download_shelf_is_visible_ && 7925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) (view_->style() == StatusView::STYLE_FLOATING || 7935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) view_->style() == StatusView::STYLE_BOTTOM))) { 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The offset is still too large. Move the bubble to the right and reset 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Y offset_ to zero. 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->SetStyle(StatusView::STYLE_STANDARD_RIGHT); 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset_ = 0; 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Subtract border width + bubble width. 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int right_position_x = window_width - (position_.x() + size_.width()); 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->SetBounds(gfx::Rect(top_left.x() + right_position_x, 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) top_left.y() + position_.y(), 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_.width(), size_.height())); 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset_ = offset; 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(), 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) top_left.y() + position_.y() + offset_, 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_.width(), size_.height())); 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (offset_ != 0 || 8115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) view_->style() == StatusView::STYLE_STANDARD_RIGHT) { 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset_ = 0; 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->SetStyle(StatusView::STYLE_STANDARD); 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(), 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) top_left.y() + position_.y(), 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_.width(), size_.height())); 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool StatusBubbleViews::IsFrameVisible() { 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::Widget* frame = base_view_->GetWidget(); 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!frame->IsVisible()) 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::Widget* window = frame->GetTopLevelWidget(); 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !window || !window->IsMinimized(); 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool StatusBubbleViews::IsFrameMaximized() { 8305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) views::Widget* frame = base_view_->GetWidget(); 8315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) views::Widget* window = frame->GetTopLevelWidget(); 8325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return window && window->IsMaximized(); 8335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 8345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::ExpandBubble() { 8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Elide URL to maximum possible size, then check actual length (it may 8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // still be too long to fit) before expanding bubble. 8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect popup_bounds = popup_->GetWindowBoundsInScreen(); 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_status_bubble_width = GetMaxStatusBubbleWidth(); 8405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const gfx::FontList font_list; 8415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) url_text_ = ElideUrl(url_, font_list, max_status_bubble_width, languages_); 8425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int expanded_bubble_width = 8435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::max(GetStandardStatusBubbleWidth(), 8445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::min(gfx::GetStringWidth(url_text_, font_list) + 8455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) (kShadowThickness * 2) + kTextPositionX + 8465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kTextHorizPadding + 1, 8475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) max_status_bubble_width)); 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_expanded_ = true; 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expand_view_->StartExpansion(url_text_, popup_bounds.width(), 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expanded_bubble_width); 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatusBubbleViews::GetStandardStatusBubbleWidth() { 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return base_view_->bounds().width() / 3; 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int StatusBubbleViews::GetMaxStatusBubbleWidth() { 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ui::NativeTheme* theme = base_view_->GetNativeTheme(); 8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return static_cast<int>(std::max(0, base_view_->bounds().width() - 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding - 1 - 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::NativeScrollBar::GetVerticalScrollBarWidth(theme))); 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::SetBubbleWidth(int width) { 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_.set_width(width); 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetBounds(original_position_.x(), original_position_.y(), 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_.width(), size_.height()); 8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StatusBubbleViews::CancelExpandTimer() { 8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (expand_timer_factory_.HasWeakPtrs()) 8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expand_timer_factory_.InvalidateWeakPtrs(); 8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 874