| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 #include "views/bubble/border_contents_view.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 #include "ui/gfx/screen.h" | |
| 10 | |
| 11 static const int kTopMargin = 6; | |
| 12 static const int kLeftMargin = 6; | |
| 13 static const int kBottomMargin = 6; | |
| 14 static const int kRightMargin = 6; | |
| 15 | |
| 16 namespace { | |
| 17 | |
| 18 // Computes how much |window_bounds| is off-screen of the monitor bounds | |
| 19 // |monitor_bounds| and puts the values in |offscreen_insets|. | |
| 20 // Returns false if |window_bounds| is actually contained in |monitor_bounds|, | |
| 21 // in which case |offscreen_insets| is not modified. | |
| 22 bool ComputeOffScreenInsets(const gfx::Rect& monitor_bounds, | |
| 23 const gfx::Rect& window_bounds, | |
| 24 gfx::Insets* offscreen_insets) { | |
| 25 if (monitor_bounds.Contains(window_bounds)) | |
| 26 return false; | |
| 27 | |
| 28 if (!offscreen_insets) | |
| 29 return true; | |
| 30 | |
| 31 // window_bounds | |
| 32 // +-------------------------------+ | |
| 33 // | top | | |
| 34 // | +----------------+ | | |
| 35 // | left | monitor_bounds | right | | |
| 36 // | +----------------+ | | |
| 37 // | bottom | | |
| 38 // +-------------------------------+ | |
| 39 int top = std::max(0, monitor_bounds.y() - window_bounds.y()); | |
| 40 int left = std::max(0, monitor_bounds.x() - window_bounds.x()); | |
| 41 int bottom = std::max(0, window_bounds.bottom() - monitor_bounds.bottom()); | |
| 42 int right = std::max(0, window_bounds.right() - monitor_bounds.right()); | |
| 43 | |
| 44 offscreen_insets->Set(top, left, bottom, right); | |
| 45 return true; | |
| 46 } | |
| 47 | |
| 48 // Convenience method that returns the height of |insets| if |vertical| is | |
| 49 // true, its width otherwise. | |
| 50 int GetInsetsLength(const gfx::Insets& insets, bool vertical) { | |
| 51 return vertical ? insets.height() : insets.width(); | |
| 52 } | |
| 53 | |
| 54 } // namespace | |
| 55 | |
| 56 namespace views { | |
| 57 | |
| 58 BorderContentsView::BorderContentsView() | |
| 59 : bubble_border_(NULL), | |
| 60 content_margins_(kTopMargin, kLeftMargin, kBottomMargin, kRightMargin) { | |
| 61 } | |
| 62 | |
| 63 BorderContentsView::BorderContentsView(int top_margin, | |
| 64 int left_margin, | |
| 65 int bottom_margin, | |
| 66 int right_margin) | |
| 67 : bubble_border_(NULL), | |
| 68 content_margins_(top_margin, left_margin, bottom_margin, right_margin) { | |
| 69 } | |
| 70 | |
| 71 BorderContentsView::~BorderContentsView() {} | |
| 72 | |
| 73 void BorderContentsView::Init() { | |
| 74 // Default arrow location. | |
| 75 BubbleBorder::ArrowLocation arrow_location = | |
| 76 BubbleBorder::TOP_LEFT; | |
| 77 if (base::i18n::IsRTL()) | |
| 78 arrow_location = BubbleBorder::horizontal_mirror(arrow_location); | |
| 79 DCHECK(!bubble_border_); | |
| 80 | |
| 81 // TODO(alicet): Expose the shadow option in BorderContentsView when we make | |
| 82 // the fullscreen exit bubble use the new bubble code. | |
| 83 bubble_border_ = new BubbleBorder(arrow_location, | |
| 84 views::BubbleBorder::NO_SHADOW); | |
| 85 set_border(bubble_border_); | |
| 86 set_background(new BubbleBackground(bubble_border_)); | |
| 87 } | |
| 88 | |
| 89 void BorderContentsView::SetBackgroundColor(SkColor color) { | |
| 90 bubble_border_->set_background_color(color); | |
| 91 } | |
| 92 | |
| 93 void BorderContentsView::SetAlignment( | |
| 94 views::BubbleBorder::BubbleAlignment alignment) { | |
| 95 bubble_border_->set_alignment(alignment); | |
| 96 } | |
| 97 | |
| 98 void BorderContentsView::SizeAndGetBounds( | |
| 99 const gfx::Rect& position_relative_to, | |
| 100 BubbleBorder::ArrowLocation arrow_location, | |
| 101 bool allow_bubble_offscreen, | |
| 102 const gfx::Size& contents_size, | |
| 103 gfx::Rect* contents_bounds, | |
| 104 gfx::Rect* window_bounds) { | |
| 105 if (base::i18n::IsRTL()) | |
| 106 arrow_location = BubbleBorder::horizontal_mirror(arrow_location); | |
| 107 bubble_border_->set_arrow_location(arrow_location); | |
| 108 // Set the border. | |
| 109 set_border(bubble_border_); | |
| 110 | |
| 111 // Give the contents a margin. | |
| 112 gfx::Size local_contents_size(contents_size); | |
| 113 local_contents_size.Enlarge(content_margins_.width(), | |
| 114 content_margins_.height()); | |
| 115 | |
| 116 // Try putting the arrow in its initial location, and calculating the bounds. | |
| 117 *window_bounds = | |
| 118 bubble_border_->GetBounds(position_relative_to, local_contents_size); | |
| 119 if (!allow_bubble_offscreen) { | |
| 120 gfx::Rect monitor_bounds = GetMonitorBounds(position_relative_to); | |
| 121 if (!monitor_bounds.IsEmpty()) { | |
| 122 // Try to resize vertically if this does not fit on the screen. | |
| 123 MirrorArrowIfOffScreen(true, // |vertical|. | |
| 124 position_relative_to, monitor_bounds, | |
| 125 local_contents_size, &arrow_location, | |
| 126 window_bounds); | |
| 127 // Then try to resize horizontally if it still does not fit on the screen. | |
| 128 MirrorArrowIfOffScreen(false, // |vertical|. | |
| 129 position_relative_to, monitor_bounds, | |
| 130 local_contents_size, &arrow_location, | |
| 131 window_bounds); | |
| 132 } | |
| 133 } | |
| 134 | |
| 135 // Calculate the bounds of the contained contents (in window coordinates) by | |
| 136 // subtracting the border dimensions and margin amounts. | |
| 137 *contents_bounds = gfx::Rect(gfx::Point(), window_bounds->size()); | |
| 138 gfx::Insets insets; | |
| 139 bubble_border_->GetInsets(&insets); | |
| 140 insets += content_margins_; | |
| 141 contents_bounds->Inset(insets); | |
| 142 } | |
| 143 | |
| 144 gfx::Rect BorderContentsView::GetMonitorBounds(const gfx::Rect& rect) { | |
| 145 return gfx::Screen::GetMonitorWorkAreaNearestPoint(rect.CenterPoint()); | |
| 146 } | |
| 147 | |
| 148 void BorderContentsView::MirrorArrowIfOffScreen( | |
| 149 bool vertical, | |
| 150 const gfx::Rect& position_relative_to, | |
| 151 const gfx::Rect& monitor_bounds, | |
| 152 const gfx::Size& local_contents_size, | |
| 153 BubbleBorder::ArrowLocation* arrow_location, | |
| 154 gfx::Rect* window_bounds) { | |
| 155 // If the bounds don't fit, move the arrow to its mirrored position to see if | |
| 156 // it improves things. | |
| 157 gfx::Insets offscreen_insets; | |
| 158 if (ComputeOffScreenInsets(monitor_bounds, *window_bounds, | |
| 159 &offscreen_insets) && | |
| 160 GetInsetsLength(offscreen_insets, vertical) > 0) { | |
| 161 BubbleBorder::ArrowLocation original_arrow_location = | |
| 162 *arrow_location; | |
| 163 *arrow_location = | |
| 164 vertical ? BubbleBorder::vertical_mirror(*arrow_location) : | |
| 165 BubbleBorder::horizontal_mirror(*arrow_location); | |
| 166 | |
| 167 // Change the arrow and get the new bounds. | |
| 168 bubble_border_->set_arrow_location(*arrow_location); | |
| 169 *window_bounds = bubble_border_->GetBounds(position_relative_to, | |
| 170 local_contents_size); | |
| 171 gfx::Insets new_offscreen_insets; | |
| 172 // If there is more of the window offscreen, we'll keep the old arrow. | |
| 173 if (ComputeOffScreenInsets(monitor_bounds, *window_bounds, | |
| 174 &new_offscreen_insets) && | |
| 175 GetInsetsLength(new_offscreen_insets, vertical) >= | |
| 176 GetInsetsLength(offscreen_insets, vertical)) { | |
| 177 *arrow_location = original_arrow_location; | |
| 178 bubble_border_->set_arrow_location(*arrow_location); | |
| 179 *window_bounds = bubble_border_->GetBounds(position_relative_to, | |
| 180 local_contents_size); | |
| 181 } | |
| 182 } | |
| 183 } | |
| 184 | |
| 185 } // namespace views | |
| OLD | NEW |