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 UI_VIEWS_BUBBLE_BUBBLE_FRAME_VIEW_H_ 6 #define UI_VIEWS_BUBBLE_BUBBLE_FRAME_VIEW_H_ 7 8 #include <memory> 9 10 #include "base/compiler_specific.h" 11 #include "base/gtest_prod_util.h" 12 #include "base/macros.h" 13 #include "base/time/time.h" 14 #include "ui/gfx/font_list.h" 15 #include "ui/gfx/geometry/insets.h" 16 #include "ui/views/bubble/bubble_border.h" 17 #include "ui/views/controls/button/button.h" 18 #include "ui/views/controls/label.h" 19 #include "ui/views/controls/progress_bar.h" 20 #include "ui/views/input_event_activation_protector.h" 21 #include "ui/views/window/non_client_view.h" 22 23 namespace views { 24 25 class FootnoteContainerView; 26 class ImageView; 27 28 // The non-client frame view of bubble-styled widgets. 29 class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView, 30 public ButtonListener { 31 public: 32 enum class PreferredArrowAdjustment { kMirror, kOffset }; 33 34 // Internal class name. 35 static const char kViewClassName[]; 36 37 BubbleFrameView(const gfx::Insets& title_margins, 38 const gfx::Insets& content_margins); 39 ~BubbleFrameView() override; 40 41 static std::unique_ptr<Label> CreateDefaultTitleLabel( 42 const base::string16& title_text); 43 44 // Creates a close button used in the corner of the dialog. 45 static std::unique_ptr<Button> CreateCloseButton(ButtonListener* listener); 46 47 // NonClientFrameView: 48 gfx::Rect GetBoundsForClientView() const override; 49 gfx::Rect GetWindowBoundsForClientBounds( 50 const gfx::Rect& client_bounds) const override; 51 bool GetClientMask(const gfx::Size& size, SkPath* path) const override; 52 int NonClientHitTest(const gfx::Point& point) override; 53 void GetWindowMask(const gfx::Size& size, SkPath* window_mask) override; 54 void ResetWindowControls() override; 55 void UpdateWindowIcon() override; 56 void UpdateWindowTitle() override; 57 void SizeConstraintsChanged() override; 58 59 // Sets a custom view to be the dialog title instead of the |default_title_| 60 // label. If there is an existing title view it will be deleted. 61 void SetTitleView(std::unique_ptr<View> title_view); 62 63 // Updates the current progress value of |progress_indicator_|. If progress is 64 // absent, hides |the progress_indicator|. 65 void SetProgress(base::Optional<double> progress); 66 67 // View: 68 const char* GetClassName() const override; 69 gfx::Size CalculatePreferredSize() const override; 70 gfx::Size GetMinimumSize() const override; 71 gfx::Size GetMaximumSize() const override; 72 void Layout() override; 73 void OnPaint(gfx::Canvas* canvas) override; 74 void PaintChildren(const PaintInfo& paint_info) override; 75 void OnThemeChanged() override; 76 void ViewHierarchyChanged( 77 const ViewHierarchyChangedDetails& details) override; 78 void VisibilityChanged(View* starting_from, bool is_visible) override; 79 80 // ButtonListener: 81 void ButtonPressed(Button* sender, const ui::Event& event) override; 82 83 // Use SetBubbleBorder() not SetBorder(). 84 void SetBubbleBorder(std::unique_ptr<BubbleBorder> border); 85 title()86 const View* title() const { 87 return custom_title_ ? custom_title_ : default_title_; 88 } title()89 View* title() { 90 return const_cast<View*>( 91 static_cast<const BubbleFrameView*>(this)->title()); 92 } 93 content_margins()94 gfx::Insets content_margins() const { return content_margins_; } 95 96 // Sets a custom header view for the dialog. If there is an existing header 97 // view it will be deleted. The header view will be inserted above the title, 98 // so outside the content bounds. If there is a close button, it will be shown 99 // in front of the header view and will overlap with it. The title will be 100 // shown below the header and / or the close button, depending on which is 101 // lower. An example usage for a header view would be a banner image. 102 void SetHeaderView(std::unique_ptr<View> view); 103 104 // Sets a custom footnote view for the dialog. If there is an existing 105 // footnote view it will be deleted. The footnote will be rendered at the 106 // bottom of the bubble, after the content view. It is separated by a 1 dip 107 // line and has a solid background by being embedded in a 108 // FootnoteContainerView. An example footnote would be some help text. 109 void SetFootnoteView(std::unique_ptr<View> view); 110 View* GetFootnoteView() const; set_footnote_margins(const gfx::Insets & footnote_margins)111 void set_footnote_margins(const gfx::Insets& footnote_margins) { 112 footnote_margins_ = footnote_margins; 113 } 114 set_preferred_arrow_adjustment(PreferredArrowAdjustment adjustment)115 void set_preferred_arrow_adjustment(PreferredArrowAdjustment adjustment) { 116 preferred_arrow_adjustment_ = adjustment; 117 } 118 119 // TODO(crbug.com/1007604): remove this in favor of using 120 // Widget::InitParams::accept_events. In the mean time, don't add new uses of 121 // this flag. hit_test_transparent()122 bool hit_test_transparent() const { return hit_test_transparent_; } set_hit_test_transparent(bool hit_test_transparent)123 void set_hit_test_transparent(bool hit_test_transparent) { 124 hit_test_transparent_ = hit_test_transparent; 125 } 126 127 // Get/set the corner radius of the bubble border. corner_radius()128 int corner_radius() const { 129 return bubble_border_ ? bubble_border_->corner_radius() : 0; 130 } 131 void SetCornerRadius(int radius); 132 133 // Set the arrow of the bubble border. 134 void SetArrow(BubbleBorder::Arrow arrow); 135 136 // Set the background color of the bubble border. 137 void SetBackgroundColor(SkColor color); 138 SkColor GetBackgroundColor() const; 139 140 // Given the size of the contents and the rect to point at, returns the bounds 141 // of the bubble window. The bubble's arrow location may change if the bubble 142 // does not fit on the monitor or anchor window (if one exists) and 143 // |adjust_to_fit_available_bounds| is true. 144 gfx::Rect GetUpdatedWindowBounds(const gfx::Rect& anchor_rect, 145 const BubbleBorder::Arrow arrow, 146 const gfx::Size& client_size, 147 bool adjust_to_fit_available_bounds); 148 GetCloseButtonForTesting()149 Button* GetCloseButtonForTesting() { return close_; } 150 GetHeaderViewForTesting()151 View* GetHeaderViewForTesting() const { return header_view_; } 152 153 // Resets the time when view has been shown. Tests may need to call this 154 // method if they use events that could be otherwise treated as unintended. 155 // See IsPossiblyUnintendedInteraction(). 156 void ResetViewShownTimeStampForTesting(); 157 158 protected: 159 // Returns the available screen bounds if the frame were to show in |rect|. 160 virtual gfx::Rect GetAvailableScreenBounds(const gfx::Rect& rect) const; 161 162 // Returns the available anchor window bounds in the screen. 163 virtual gfx::Rect GetAvailableAnchorWindowBounds() const; 164 165 // Override and return true to allow client view to overlap into the title 166 // area when HasTitle() returns false and/or ShouldShowCloseButton() returns 167 // true. Returns false by default. 168 virtual bool ExtendClientIntoTitle() const; 169 170 bool IsCloseButtonVisible() const; 171 gfx::Rect GetCloseButtonMirroredBounds() const; 172 bubble_border_for_testing()173 BubbleBorder* bubble_border_for_testing() const { return bubble_border_; } 174 175 private: 176 FRIEND_TEST_ALL_PREFIXES(BubbleFrameViewTest, RemoveFootnoteView); 177 FRIEND_TEST_ALL_PREFIXES(BubbleFrameViewTest, LayoutWithIcon); 178 FRIEND_TEST_ALL_PREFIXES(BubbleFrameViewTest, LayoutWithProgressIndicator); 179 FRIEND_TEST_ALL_PREFIXES(BubbleFrameViewTest, IgnorePossiblyUnintendedClicks); 180 FRIEND_TEST_ALL_PREFIXES(BubbleDelegateTest, CloseReasons); 181 FRIEND_TEST_ALL_PREFIXES(BubbleDialogDelegateViewTest, CloseMethods); 182 FRIEND_TEST_ALL_PREFIXES(BubbleDialogDelegateViewTest, CreateDelegate); 183 184 // Mirrors the bubble's arrow location on the |vertical| or horizontal axis, 185 // if the generated window bounds don't fit in the given available bounds. 186 void MirrorArrowIfOutOfBounds(bool vertical, 187 const gfx::Rect& anchor_rect, 188 const gfx::Size& client_size, 189 const gfx::Rect& available_bounds); 190 191 // Adjust the bubble's arrow offsets if the generated window bounds don't fit 192 // in the given available bounds. 193 void OffsetArrowIfOutOfBounds(const gfx::Rect& anchor_rect, 194 const gfx::Size& client_size, 195 const gfx::Rect& available_bounds); 196 197 // The width of the frame for the given |client_width|. The result accounts 198 // for the minimum title bar width and includes all insets and possible 199 // snapping. It does not include the border. 200 int GetFrameWidthForClientWidth(int client_width) const; 201 202 // Calculates the size needed to accommodate the given client area. 203 gfx::Size GetFrameSizeForClientSize(const gfx::Size& client_size) const; 204 205 // True if the frame has a title area. This is the area affected by 206 // |title_margins_|, including the icon and title text, but not the close 207 // button. 208 bool HasTitle() const; 209 210 // The insets of the text portion of the title, based on |title_margins_| and 211 // whether there is an icon and/or close button. Note there may be no title, 212 // in which case only insets required for the close button are returned. 213 gfx::Insets GetTitleLabelInsetsFromFrame() const; 214 215 // The client_view insets (from the frame view) for the given |frame_width|. 216 gfx::Insets GetClientInsetsForFrameWidth(int frame_width) const; 217 218 // Gets the height of the |header_view_| given a |frame_width|. Returns zero 219 // if there is no header view or if it is not visible. 220 int GetHeaderHeightForFrameWidth(int frame_width) const; 221 222 // The bubble border. 223 BubbleBorder* bubble_border_ = nullptr; 224 225 // Margins around the title label. 226 gfx::Insets title_margins_; 227 228 // Margins between the content and the inside of the border, in pixels. 229 gfx::Insets content_margins_; 230 231 // Margins between the footnote view and the footnote container. 232 gfx::Insets footnote_margins_; 233 234 // The optional title icon. 235 ImageView* title_icon_ = nullptr; 236 237 // One of these fields is used as the dialog title. If SetTitleView is called 238 // the custom title view is stored in |custom_title_| and this class assumes 239 // ownership. Otherwise |default_title_| is used. 240 Label* default_title_ = nullptr; 241 View* custom_title_ = nullptr; 242 243 // The optional close button (the X). 244 Button* close_ = nullptr; 245 246 // The optional progress bar. Used to indicate bubble pending state. By 247 // default it is invisible. 248 ProgressBar* progress_indicator_ = nullptr; 249 250 // The optional header view. 251 View* header_view_ = nullptr; 252 253 // A view to contain the footnote view, if it exists. 254 FootnoteContainerView* footnote_container_ = nullptr; 255 256 // Set preference for how the arrow will be adjusted if the window is outside 257 // the available bounds. 258 PreferredArrowAdjustment preferred_arrow_adjustment_ = 259 PreferredArrowAdjustment::kMirror; 260 261 // If true the view is transparent to all hit tested events (i.e. click and 262 // hover). DEPRECATED: See note above set_hit_test_transparent(). 263 bool hit_test_transparent_ = false; 264 265 InputEventActivationProtector input_protector_; 266 267 DISALLOW_COPY_AND_ASSIGN(BubbleFrameView); 268 }; 269 270 } // namespace views 271 272 #endif // UI_VIEWS_BUBBLE_BUBBLE_FRAME_VIEW_H_ 273