1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef CHROME_BROWSER_UI_VIEWS_STATUS_BUBBLE_VIEWS_H_
6 #define CHROME_BROWSER_UI_VIEWS_STATUS_BUBBLE_VIEWS_H_
7 
8 #include <memory>
9 
10 #include "base/compiler_specific.h"
11 #include "base/macros.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/strings/string16.h"
14 #include "chrome/browser/ui/status_bubble.h"
15 #include "ui/gfx/geometry/rect.h"
16 #include "url/gurl.h"
17 
18 namespace base {
19 class SequencedTaskRunner;
20 }
21 namespace gfx {
22 class Animation;
23 class Point;
24 }
25 namespace views {
26 class View;
27 class Widget;
28 }
29 
30 // StatusBubble displays a bubble of text that fades in, hovers over the
31 // browser chrome and fades away when not needed. It is primarily designed
32 // to allow users to see where hovered links point to.
33 class StatusBubbleViews : public StatusBubble {
34  public:
35   // How wide the bubble's shadow is.
36   static const int kShadowThickness;
37 
38   // The combined vertical padding above and below the text.
39   static const int kTotalVerticalPadding = 7;
40 
41   // |base_view| is the view that this bubble is positioned relative to.
42   explicit StatusBubbleViews(views::View* base_view);
43   ~StatusBubbleViews() override;
44 
base_view()45   views::View* base_view() { return base_view_; }
46 
47   // Reposition the bubble's popup - as we are using a WS_POPUP for the bubble,
48   // we have to manually position it when the browser window moves.
49   void RepositionPopup();
50 
51   // The bubble only has a preferred height: the sum of the height of
52   // the font and kTotalVerticalPadding.
53   int GetPreferredHeight();
54 
55   // Calculate and set new position for status bubble.
56   void Reposition();
57 
58   // Set bubble to new width.
59   void SetBubbleWidth(int width);
60 
61   // Gets the width that a bubble should be for a given string
62   int GetWidthForURL(const base::string16& url_string);
63 
64   // Notifies the bubble's popup that browser's theme is changed.
65   void OnThemeChanged();
66 
67   // Overridden from StatusBubble:
68   void SetStatus(const base::string16& status) override;
69   void SetURL(const GURL& url) override;
70   void Hide() override;
71   void MouseMoved(bool left_content) override;
72   void UpdateDownloadShelfVisibility(bool visible) override;
73 
74  protected:
popup()75   views::Widget* popup() { return popup_.get(); }
76 
77   // Notify a mouse event with current mouse location. The location is (0,0)
78   // when the mouse is at the top-left of the screen.
79   void MouseMovedAt(const gfx::Point& location, bool left_content);
80 
81  private:
82   class StatusView;
83   class StatusViewAnimation;
84   class StatusViewExpander;
85 
86   friend class StatusBubbleViewsTest;
87   friend class StatusView;
88 
89   // Initializes the popup and view.
90   void InitPopup();
91 
92   // Destroys the popup and view.
93   void DestroyPopup();
94 
95   // Attempt to move the status bubble out of the way of the cursor, allowing
96   // users to see links in the region normally occupied by the status bubble.
97   void AvoidMouse(const gfx::Point& location);
98 
99   // Returns true if the base_view_'s widget is visible and not minimized.
100   bool IsFrameVisible();
101 
102   // Returns true if the base_view_'s widget is maximized.
103   bool IsFrameMaximized();
104 
105   // Expand bubble size to accommodate a long URL.
106   void ExpandBubble();
107 
108   // Cancel all waiting expansion animations in the timer.
109   void CancelExpandTimer();
110 
111   // Get the standard width for a status bubble in the current frame size.
112   int GetStandardStatusBubbleWidth();
113 
114   // Get the maximum possible width for a status bubble in the current frame
115   // size.
116   int GetMaxStatusBubbleWidth();
117 
118   // Set the bounds of the bubble relative to |base_view_|.
119   void SetBounds(int x, int y, int w, int h);
120 
121   gfx::Animation* GetShowHideAnimationForTest();
122   bool IsDestroyPopupTimerRunningForTest();
123 
124   // The status text we want to display when there are no URLs to display.
125   base::string16 status_text_;
126 
127   // The url we want to display when there is no status text to display.
128   base::string16 url_text_;
129 
130   // The original, non-elided URL.
131   GURL url_;
132 
133   // Position relative to the base_view_.
134   gfx::Point original_position_;
135   // original_position_ adjusted according to the current RTL.
136   gfx::Point position_;
137   gfx::Size size_;
138 
139   // Last location passed to MouseMoved().
140   gfx::Point last_mouse_moved_location_;
141 
142   // Whether the view contains the mouse.
143   bool contains_mouse_ = false;
144 
145   // How vertically offset the bubble is from its root position_.
146   int offset_ = 0;
147 
148   // Use a Widget for the popup so that it floats above all content as well as
149   // going outside the bounds of the hosting widget.
150   std::unique_ptr<views::Widget> popup_;
151 
152   views::View* base_view_;
153   StatusView* view_ = nullptr;
154 
155   // Manages the expansion of a status bubble to fit a long URL.
156   std::unique_ptr<StatusViewExpander> expand_view_;
157 
158   // If the download shelf is visible, do not obscure it.
159   bool download_shelf_is_visible_ = false;
160 
161   // If the bubble has already been expanded, and encounters a new URL,
162   // change size immediately, with no hover.
163   bool is_expanded_ = false;
164 
165   // Used for posting tasks. This is typically
166   // base::ThreadTaskRunnerHandle::Get(), but may be set to something else for
167   // tests.
168   base::SequencedTaskRunner* task_runner_;
169 
170   // Times expansion of status bubble when URL is too long for standard width.
171   base::WeakPtrFactory<StatusBubbleViews> expand_timer_factory_{this};
172 
173   DISALLOW_COPY_AND_ASSIGN(StatusBubbleViews);
174 };
175 
176 #endif  // CHROME_BROWSER_UI_VIEWS_STATUS_BUBBLE_VIEWS_H_
177