OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ash/system/tray/tray_bubble_view.h" | 5 #include "ash/system/tray/tray_bubble_view.h" |
6 | 6 |
7 #include "ash/shell.h" | 7 #include "ash/shell.h" |
8 #include "ash/shell_window_ids.h" | 8 #include "ash/shell_window_ids.h" |
9 #include "ash/system/tray/tray_constants.h" | 9 #include "ash/system/tray/tray_constants.h" |
10 #include "ash/wm/shelf_layout_manager.h" | 10 #include "ash/wm/shelf_layout_manager.h" |
| 11 #include "ash/wm/window_animations.h" |
11 #include "grit/ash_strings.h" | 12 #include "grit/ash_strings.h" |
12 #include "third_party/skia/include/core/SkCanvas.h" | 13 #include "third_party/skia/include/core/SkCanvas.h" |
13 #include "third_party/skia/include/core/SkColor.h" | 14 #include "third_party/skia/include/core/SkColor.h" |
14 #include "third_party/skia/include/core/SkPaint.h" | 15 #include "third_party/skia/include/core/SkPaint.h" |
15 #include "third_party/skia/include/core/SkPath.h" | 16 #include "third_party/skia/include/core/SkPath.h" |
16 #include "third_party/skia/include/effects/SkBlurImageFilter.h" | 17 #include "third_party/skia/include/effects/SkBlurImageFilter.h" |
17 #include "ui/aura/event.h" | 18 #include "ui/aura/event.h" |
18 #include "ui/aura/window.h" | 19 #include "ui/aura/window.h" |
19 #include "ui/base/accessibility/accessible_view_state.h" | 20 #include "ui/base/accessibility/accessible_view_state.h" |
20 #include "ui/base/l10n/l10n_util.h" | 21 #include "ui/base/l10n/l10n_util.h" |
21 #include "ui/gfx/canvas.h" | 22 #include "ui/gfx/canvas.h" |
22 #include "ui/gfx/insets.h" | 23 #include "ui/gfx/insets.h" |
23 #include "ui/gfx/screen.h" | 24 #include "ui/gfx/screen.h" |
24 #include "ui/views/bubble/bubble_frame_view.h" | 25 #include "ui/views/bubble/bubble_frame_view.h" |
25 #include "ui/views/layout/box_layout.h" | 26 #include "ui/views/layout/box_layout.h" |
26 | 27 |
27 namespace ash { | 28 namespace ash { |
28 | 29 |
29 namespace { | 30 namespace { |
30 | 31 |
31 const int kShadowThickness = 4; | 32 const int kShadowThickness = 4; |
32 const int kBottomLineHeight = 1; | 33 const int kBottomLineHeight = 1; |
33 const int kSystemTrayBubbleHorizontalInset = 1; | 34 const int kSystemTrayBubbleHorizontalInset = 1; |
34 const int kSystemTrayBubbleVerticalInset = 1; | 35 const int kSystemTrayBubbleVerticalInset = 1; |
35 | 36 |
36 const int kArrowHeight = 9; | 37 const int kArrowHeight = 9; |
37 const int kArrowWidth = 19; | 38 const int kArrowWidth = 19; |
38 | 39 |
39 // Inset the arrow a bit from the edge. | 40 // Inset the arrow a bit from the edge. |
40 const int kArrowMinOffset = kArrowWidth / 2 + 4; | 41 const int kArrowEdgeMargin = 12; |
| 42 const int kArrowMinOffset = kArrowWidth / 2 + kArrowEdgeMargin; |
41 | 43 |
42 const SkColor kShadowColor = SkColorSetARGB(0xff, 0, 0, 0); | 44 const SkColor kShadowColor = SkColorSetARGB(0xff, 0, 0, 0); |
43 | 45 |
| 46 const int kAnimationDurationForPopupMS = 200; |
| 47 |
44 void DrawBlurredShadowAroundView(gfx::Canvas* canvas, | 48 void DrawBlurredShadowAroundView(gfx::Canvas* canvas, |
45 int top, | 49 int top, |
46 int bottom, | 50 int bottom, |
47 int width, | 51 int width, |
48 const gfx::Insets& inset) { | 52 const gfx::Insets& inset) { |
49 SkPath path; | 53 SkPath path; |
50 path.incReserve(4); | 54 path.incReserve(4); |
51 path.moveTo(SkIntToScalar(inset.left() + kShadowThickness), | 55 path.moveTo(SkIntToScalar(inset.left() + kShadowThickness), |
52 SkIntToScalar(top + kShadowThickness + 1)); | 56 SkIntToScalar(top + kShadowThickness + 1)); |
53 path.lineTo(SkIntToScalar(inset.left() + kShadowThickness), | 57 path.lineTo(SkIntToScalar(inset.left() + kShadowThickness), |
(...skipping 11 matching lines...) Expand all Loading... |
65 paint.setImageFilter(new SkBlurImageFilter( | 69 paint.setImageFilter(new SkBlurImageFilter( |
66 SkIntToScalar(3), SkIntToScalar(3)))->unref(); | 70 SkIntToScalar(3), SkIntToScalar(3)))->unref(); |
67 canvas->sk_canvas()->drawPath(path, paint); | 71 canvas->sk_canvas()->drawPath(path, paint); |
68 } | 72 } |
69 | 73 |
70 class TrayBubbleBorder : public views::BubbleBorder { | 74 class TrayBubbleBorder : public views::BubbleBorder { |
71 public: | 75 public: |
72 TrayBubbleBorder(views::View* owner, | 76 TrayBubbleBorder(views::View* owner, |
73 views::View* anchor, | 77 views::View* anchor, |
74 views::BubbleBorder::ArrowLocation arrow_location, | 78 views::BubbleBorder::ArrowLocation arrow_location, |
75 int arrow_offset) | 79 int arrow_offset, |
76 : views::BubbleBorder(arrow_location, | 80 const SkColor& arrow_color) |
77 views::BubbleBorder::NO_SHADOW), | 81 : views::BubbleBorder(arrow_location, views::BubbleBorder::NO_SHADOW), |
78 owner_(owner), | 82 owner_(owner), |
79 anchor_(anchor), | 83 anchor_(anchor), |
80 tray_arrow_offset_(arrow_offset) { | 84 tray_arrow_offset_(arrow_offset) { |
81 set_alignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); | 85 set_alignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); |
| 86 set_background_color(arrow_color); |
82 } | 87 } |
83 | 88 |
84 virtual ~TrayBubbleBorder() {} | 89 virtual ~TrayBubbleBorder() {} |
85 | 90 |
86 private: | |
87 views::Background* FindAppropriateBackground(views::View* view, | |
88 const gfx::Point& point) const { | |
89 views::Background* background = NULL; | |
90 views::View* target = view->GetEventHandlerForPoint(point); | |
91 for (; target && !background; target = target->parent()) | |
92 background = target->background(); | |
93 return background; | |
94 } | |
95 | |
96 // Overridden from views::BubbleBorder. | 91 // Overridden from views::BubbleBorder. |
97 // Override views::BubbleBorder to set the bubble on top of the anchor when | 92 // Override views::BubbleBorder to set the bubble on top of the anchor when |
98 // it has no arrow. | 93 // it has no arrow. |
99 virtual gfx::Rect GetBounds(const gfx::Rect& position_relative_to, | 94 virtual gfx::Rect GetBounds(const gfx::Rect& position_relative_to, |
100 const gfx::Size& contents_size) const OVERRIDE { | 95 const gfx::Size& contents_size) const OVERRIDE { |
101 if (arrow_location() != NONE) { | 96 if (arrow_location() != NONE) { |
102 return views::BubbleBorder::GetBounds(position_relative_to, | 97 return views::BubbleBorder::GetBounds(position_relative_to, |
103 contents_size); | 98 contents_size); |
104 } | 99 } |
105 | 100 |
106 gfx::Size border_size(contents_size); | 101 gfx::Size border_size(contents_size); |
107 gfx::Insets insets; | 102 gfx::Insets insets; |
108 GetInsets(&insets); | 103 GetInsets(&insets); |
109 border_size.Enlarge(insets.width(), insets.height()); | 104 border_size.Enlarge(insets.width(), insets.height()); |
110 | 105 |
111 const int kArrowOverlap = 3; | 106 const int kArrowOverlap = 3; |
112 int x = position_relative_to.x() + | 107 int x = position_relative_to.x() + |
113 position_relative_to.width() / 2 - border_size.width() / 2; | 108 position_relative_to.width() / 2 - border_size.width() / 2; |
114 // Position the bubble on top of the anchor. | 109 // Position the bubble on top of the anchor. |
115 int y = position_relative_to.y() + | 110 int y = position_relative_to.y() + |
116 kArrowOverlap - border_size.height(); | 111 kArrowOverlap - border_size.height(); |
117 return gfx::Rect(x, y, border_size.width(), border_size.height()); | 112 return gfx::Rect(x, y, border_size.width(), border_size.height()); |
118 } | 113 } |
119 | 114 |
| 115 // TrayBubbleView supports dynamically updated bubbles. This does not |
| 116 // behave well with BubbleFrameView which expects arrow_location to be |
| 117 // unmirrored during initial layout (when ClientView is constructed), |
| 118 // then mirrored after SizeToContents() gets called. |
| 119 // So, instead of mirroring the arrow in CreateNonClientFrameView, |
| 120 // mirror it here instead. |
| 121 // TODO(stevenjb): Fix this in ui/views/bubble: crbug.com/139813 |
| 122 virtual void GetInsets(gfx::Insets* insets) const OVERRIDE { |
| 123 ArrowLocation arrow_loc = arrow_location(); |
| 124 if (base::i18n::IsRTL()) |
| 125 arrow_loc = horizontal_mirror(arrow_loc); |
| 126 return GetInsetsForArrowLocation(insets, arrow_loc); |
| 127 } |
| 128 |
120 // Overridden from views::Border. | 129 // Overridden from views::Border. |
121 virtual void Paint(const views::View& view, | 130 virtual void Paint(const views::View& view, |
122 gfx::Canvas* canvas) const OVERRIDE { | 131 gfx::Canvas* canvas) const OVERRIDE { |
123 gfx::Insets inset; | 132 gfx::Insets inset; |
124 GetInsets(&inset); | 133 // Get the unmirrored insets for the arrow location; the tray bubbles are |
| 134 // never mirrored for RTL (since that would put them off screen). |
| 135 GetInsetsForArrowLocation(&inset, arrow_location()); |
125 DrawBlurredShadowAroundView( | 136 DrawBlurredShadowAroundView( |
126 canvas, 0, owner_->height(), owner_->width(), inset); | 137 canvas, 0, owner_->height(), owner_->width(), inset); |
127 | 138 |
128 // Draw the bottom line. | 139 // Draw the bottom line. |
129 int y = owner_->height() + inset.top(); | 140 int y = owner_->height() + inset.top(); |
130 canvas->FillRect(gfx::Rect(inset.left(), y, owner_->width(), | 141 canvas->FillRect(gfx::Rect(inset.left(), y, owner_->width(), |
131 kBottomLineHeight), kBorderDarkColor); | 142 kBottomLineHeight), kBorderDarkColor); |
132 | 143 |
133 if (!Shell::GetInstance()->shelf()->IsVisible() || | 144 if (!Shell::GetInstance()->shelf()->IsVisible() || |
134 arrow_location() == views::BubbleBorder::NONE) | 145 arrow_location() == views::BubbleBorder::NONE) |
135 return; | 146 return; |
136 | 147 |
137 gfx::Point arrow_reference; | 148 gfx::Point arrow_reference; |
138 | 149 |
139 // Draw the arrow after drawing child borders, so that the arrow can cover | 150 // Draw the arrow after drawing child borders, so that the arrow can cover |
140 // the its overlap section with child border. | 151 // its overlap section with child border. |
141 SkPath path; | 152 SkPath path; |
142 path.incReserve(4); | 153 path.incReserve(4); |
143 if (arrow_location() == views::BubbleBorder::BOTTOM_RIGHT || | 154 if (arrow_location() == views::BubbleBorder::BOTTOM_RIGHT || |
144 arrow_location() == views::BubbleBorder::BOTTOM_LEFT) { | 155 arrow_location() == views::BubbleBorder::BOTTOM_LEFT) { |
145 // Do not let the arrow too close to the edge of the bubble and | 156 // Note: tray_arrow_offset_ is relative to the anchor widget. |
146 // and the edge of the anchor. | 157 int tip_x; |
147 int tip_x = base::i18n::IsRTL() ? | 158 if (tray_arrow_offset_ == |
148 std::min(std::max(tray_arrow_offset_, kArrowMinOffset), | 159 internal::TrayBubbleView::InitParams::kArrowDefaultOffset) { |
149 std::min(owner_->width(), anchor_->width()) | 160 if (arrow_location() == views::BubbleBorder::BOTTOM_LEFT) |
150 - kArrowMinOffset) : | 161 tip_x = kArrowMinOffset; |
151 std::min(std::max(owner_->width() - tray_arrow_offset_, | 162 else |
152 owner_->width() - | 163 tip_x = owner_->width() - kArrowMinOffset; |
153 std::min(owner_->width(), anchor_->width()) + | 164 } else { |
154 kArrowMinOffset), | 165 gfx::Point pt(tray_arrow_offset_, 0); |
155 owner_->width() - kArrowMinOffset); | 166 views::View::ConvertPointToScreen( |
| 167 anchor_->GetWidget()->GetRootView(), &pt); |
| 168 views::View::ConvertPointFromScreen( |
| 169 owner_->GetWidget()->GetRootView(), &pt); |
| 170 tip_x = std::min(pt.x(), owner_->width() - kArrowMinOffset); |
| 171 tip_x = std::max(tip_x, kArrowMinOffset); |
| 172 } |
156 int left_base_x = tip_x - kArrowWidth / 2; | 173 int left_base_x = tip_x - kArrowWidth / 2; |
157 int left_base_y = y; | 174 int left_base_y = y; |
158 int tip_y = left_base_y + kArrowHeight; | 175 int tip_y = left_base_y + kArrowHeight; |
159 path.moveTo(SkIntToScalar(left_base_x), SkIntToScalar(left_base_y)); | 176 path.moveTo(SkIntToScalar(left_base_x), SkIntToScalar(left_base_y)); |
160 path.lineTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y)); | 177 path.lineTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y)); |
161 path.lineTo(SkIntToScalar(left_base_x + kArrowWidth), | 178 path.lineTo(SkIntToScalar(left_base_x + kArrowWidth), |
162 SkIntToScalar(left_base_y)); | 179 SkIntToScalar(left_base_y)); |
163 arrow_reference.SetPoint(tip_x, left_base_y - kArrowHeight); | 180 arrow_reference.SetPoint(tip_x, left_base_y - kArrowHeight); |
164 } else { | 181 } else { |
165 int tip_y = y - tray_arrow_offset_; | 182 int tip_y; |
166 tip_y = std::min(std::max(kArrowMinOffset, tip_y), | 183 if (tray_arrow_offset_ == |
167 owner_->height() - kArrowMinOffset); | 184 internal::TrayBubbleView::InitParams::kArrowDefaultOffset) { |
| 185 tip_y = owner_->height() - kArrowMinOffset; |
| 186 } else { |
| 187 int pty = y - tray_arrow_offset_; |
| 188 gfx::Point pt(0, pty); |
| 189 views::View::ConvertPointToScreen( |
| 190 anchor_->GetWidget()->GetRootView(), &pt); |
| 191 views::View::ConvertPointFromScreen( |
| 192 owner_->GetWidget()->GetRootView(), &pt); |
| 193 tip_y = std::min(pt.y(), owner_->height() - kArrowMinOffset); |
| 194 tip_y = std::max(tip_y, kArrowMinOffset); |
| 195 } |
168 int top_base_y = tip_y - kArrowWidth / 2; | 196 int top_base_y = tip_y - kArrowWidth / 2; |
169 int top_base_x, tip_x; | 197 int top_base_x, tip_x; |
170 if (arrow_location() == views::BubbleBorder::LEFT_BOTTOM) { | 198 if (arrow_location() == views::BubbleBorder::LEFT_BOTTOM) { |
171 top_base_x = inset.left() + kSystemTrayBubbleHorizontalInset; | 199 top_base_x = inset.left() + kSystemTrayBubbleHorizontalInset; |
172 tip_x = top_base_x - kArrowHeight; | 200 tip_x = top_base_x - kArrowHeight; |
173 arrow_reference.SetPoint(top_base_x + kArrowHeight, tip_y); | 201 arrow_reference.SetPoint(top_base_x + kArrowHeight, tip_y); |
174 } else { | 202 } else { |
175 DCHECK(arrow_location() == views::BubbleBorder::RIGHT_BOTTOM); | 203 DCHECK(arrow_location() == views::BubbleBorder::RIGHT_BOTTOM); |
176 top_base_x = inset.left() + owner_->width() - | 204 top_base_x = inset.left() + owner_->width() - |
177 kSystemTrayBubbleHorizontalInset; | 205 kSystemTrayBubbleHorizontalInset; |
178 tip_x = top_base_x + kArrowHeight; | 206 tip_x = top_base_x + kArrowHeight; |
179 arrow_reference.SetPoint(top_base_x - kArrowHeight, tip_y); | 207 arrow_reference.SetPoint(top_base_x - kArrowHeight, tip_y); |
180 } | 208 } |
181 path.moveTo(SkIntToScalar(top_base_x), SkIntToScalar(top_base_y)); | 209 path.moveTo(SkIntToScalar(top_base_x), SkIntToScalar(top_base_y)); |
182 path.lineTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y)); | 210 path.lineTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y)); |
183 path.lineTo(SkIntToScalar(top_base_x), | 211 path.lineTo(SkIntToScalar(top_base_x), |
184 SkIntToScalar(top_base_y + kArrowWidth)); | 212 SkIntToScalar(top_base_y + kArrowWidth)); |
185 } | 213 } |
186 | 214 |
187 views::Background* background = FindAppropriateBackground(owner_, | |
188 arrow_reference); | |
189 | |
190 SkPaint paint; | 215 SkPaint paint; |
191 paint.setAntiAlias(true); | 216 paint.setAntiAlias(true); |
192 paint.setStyle(SkPaint::kFill_Style); | 217 paint.setStyle(SkPaint::kFill_Style); |
193 paint.setColor(background ? background->get_color() : kBackgroundColor); | 218 paint.setColor(background_color()); |
194 canvas->DrawPath(path, paint); | 219 canvas->DrawPath(path, paint); |
195 | 220 |
196 // Now draw the arrow border. | 221 // Now draw the arrow border. |
197 paint.setStyle(SkPaint::kStroke_Style); | 222 paint.setStyle(SkPaint::kStroke_Style); |
198 paint.setColor(kBorderDarkColor); | 223 paint.setColor(kBorderDarkColor); |
199 canvas->DrawPath(path, paint); | 224 canvas->DrawPath(path, paint); |
200 | 225 |
201 } | 226 } |
202 | 227 |
203 views::View* owner_; | 228 views::View* owner_; |
204 views::View* anchor_; | 229 views::View* anchor_; |
205 const int tray_arrow_offset_; | 230 const int tray_arrow_offset_; |
206 | 231 |
207 DISALLOW_COPY_AND_ASSIGN(TrayBubbleBorder); | 232 DISALLOW_COPY_AND_ASSIGN(TrayBubbleBorder); |
208 }; | 233 }; |
209 | 234 |
210 } // namespace | 235 } // namespace |
211 | 236 |
212 namespace internal { | 237 namespace internal { |
213 | 238 |
| 239 // static |
| 240 const int TrayBubbleView::InitParams::kArrowDefaultOffset = -1; |
| 241 |
| 242 TrayBubbleView::InitParams::InitParams(AnchorType anchor_type, |
| 243 ShelfAlignment shelf_alignment) |
| 244 : anchor_type(anchor_type), |
| 245 shelf_alignment(shelf_alignment), |
| 246 bubble_width(kTrayPopupWidth), |
| 247 max_height(0), |
| 248 can_activate(false), |
| 249 arrow_offset(kArrowDefaultOffset), |
| 250 arrow_color(kHeaderBackgroundColorDark) { |
| 251 } |
| 252 |
| 253 TrayBubbleView* TrayBubbleView::Create(views::View* anchor, |
| 254 Host* host, |
| 255 const InitParams& init_params) { |
| 256 // Set arrow_location here so that it can be passed correctly to the |
| 257 // BubbleView constructor. |
| 258 views::BubbleBorder::ArrowLocation arrow_location; |
| 259 if (init_params.anchor_type == ANCHOR_TYPE_TRAY) { |
| 260 if (init_params.shelf_alignment == SHELF_ALIGNMENT_BOTTOM) { |
| 261 arrow_location = base::i18n::IsRTL() ? |
| 262 views::BubbleBorder::BOTTOM_LEFT : views::BubbleBorder::BOTTOM_RIGHT; |
| 263 } else if (init_params.shelf_alignment == SHELF_ALIGNMENT_LEFT) { |
| 264 arrow_location = views::BubbleBorder::LEFT_BOTTOM; |
| 265 } else { |
| 266 arrow_location = views::BubbleBorder::RIGHT_BOTTOM; |
| 267 } |
| 268 } else { |
| 269 arrow_location = views::BubbleBorder::NONE; |
| 270 } |
| 271 |
| 272 return new TrayBubbleView(init_params, arrow_location, anchor, host); |
| 273 } |
| 274 |
214 TrayBubbleView::TrayBubbleView( | 275 TrayBubbleView::TrayBubbleView( |
| 276 const InitParams& init_params, |
| 277 views::BubbleBorder::ArrowLocation arrow_location, |
215 views::View* anchor, | 278 views::View* anchor, |
216 views::BubbleBorder::ArrowLocation arrow_location, | 279 Host* host) |
217 Host* host, | |
218 bool can_activate, | |
219 int bubble_width) | |
220 : views::BubbleDelegateView(anchor, arrow_location), | 280 : views::BubbleDelegateView(anchor, arrow_location), |
221 host_(host), | 281 params_(init_params), |
222 can_activate_(can_activate), | 282 host_(host) { |
223 max_height_(0), | |
224 bubble_width_(bubble_width) { | |
225 set_margins(gfx::Insets()); | 283 set_margins(gfx::Insets()); |
226 set_parent_window(Shell::GetContainer( | 284 set_parent_window(Shell::GetContainer( |
227 anchor->GetWidget()->GetNativeWindow()->GetRootWindow(), | 285 anchor->GetWidget()->GetNativeWindow()->GetRootWindow(), |
228 internal::kShellWindowId_SettingBubbleContainer)); | 286 internal::kShellWindowId_SettingBubbleContainer)); |
229 set_notify_enter_exit_on_child(true); | 287 set_notify_enter_exit_on_child(true); |
230 SetPaintToLayer(true); | 288 SetPaintToLayer(true); |
231 SetFillsBoundsOpaquely(true); | 289 SetFillsBoundsOpaquely(true); |
232 } | 290 } |
233 | 291 |
234 TrayBubbleView::~TrayBubbleView() { | 292 TrayBubbleView::~TrayBubbleView() { |
235 // Inform host items (models) that their views are being destroyed. | 293 // Inform host items (models) that their views are being destroyed. |
236 if (host_) | 294 if (host_) |
237 host_->BubbleViewDestroyed(); | 295 host_->BubbleViewDestroyed(); |
238 } | 296 } |
239 | 297 |
240 void TrayBubbleView::SetBubbleBorder(int arrow_offset) { | |
241 DCHECK(GetWidget()); | |
242 TrayBubbleBorder* bubble_border = new TrayBubbleBorder( | |
243 this, anchor_view(), arrow_location(), arrow_offset); | |
244 GetBubbleFrameView()->SetBubbleBorder(bubble_border); | |
245 // Recalculate size with new border. | |
246 SizeToContents(); | |
247 } | |
248 | |
249 void TrayBubbleView::UpdateBubble() { | 298 void TrayBubbleView::UpdateBubble() { |
250 SizeToContents(); | 299 SizeToContents(); |
251 GetWidget()->GetRootView()->SchedulePaint(); | 300 GetWidget()->GetRootView()->SchedulePaint(); |
252 } | 301 } |
253 | 302 |
254 void TrayBubbleView::SetMaxHeight(int height) { | 303 void TrayBubbleView::SetMaxHeight(int height) { |
255 max_height_ = height; | 304 params_.max_height = height; |
256 if (GetWidget()) | 305 if (GetWidget()) |
257 SizeToContents(); | 306 SizeToContents(); |
258 } | 307 } |
259 | 308 |
260 void TrayBubbleView::Init() { | 309 void TrayBubbleView::Init() { |
261 views::BoxLayout* layout = | 310 views::BoxLayout* layout = |
262 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0); | 311 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0); |
263 layout->set_spread_blank_space(true); | 312 layout->set_spread_blank_space(true); |
264 SetLayoutManager(layout); | 313 SetLayoutManager(layout); |
265 set_background(NULL); | 314 set_background(NULL); |
266 } | 315 } |
267 | 316 |
268 gfx::Rect TrayBubbleView::GetAnchorRect() { | 317 gfx::Rect TrayBubbleView::GetAnchorRect() { |
269 gfx::Rect rect; | 318 gfx::Rect rect; |
270 if (host_) | 319 |
271 rect = host_->GetAnchorRect(); | 320 if (anchor_widget()->IsVisible()) { |
| 321 rect = anchor_widget()->GetWindowBoundsInScreen(); |
| 322 if (params_.anchor_type == ANCHOR_TYPE_TRAY) { |
| 323 if (params_.shelf_alignment == SHELF_ALIGNMENT_BOTTOM) { |
| 324 bool rtl = base::i18n::IsRTL(); |
| 325 rect.Inset( |
| 326 rtl ? kPaddingFromRightEdgeOfScreenBottomAlignment : 0, |
| 327 0, |
| 328 rtl ? 0 : kPaddingFromRightEdgeOfScreenBottomAlignment, |
| 329 kPaddingFromBottomOfScreenBottomAlignment); |
| 330 } else if (params_.shelf_alignment == SHELF_ALIGNMENT_LEFT) { |
| 331 rect.Inset(0, 0, kPaddingFromInnerEdgeOfLauncherVerticalAlignment, |
| 332 kPaddingFromBottomOfScreenVerticalAlignment); |
| 333 } else { |
| 334 rect.Inset(kPaddingFromInnerEdgeOfLauncherVerticalAlignment, |
| 335 0, 0, kPaddingFromBottomOfScreenVerticalAlignment); |
| 336 } |
| 337 } else if (params_.anchor_type == ANCHOR_TYPE_BUBBLE) { |
| 338 // Invert the offsets to align with the bubble below. |
| 339 if (params_.shelf_alignment == SHELF_ALIGNMENT_LEFT) { |
| 340 rect.Inset(kPaddingFromInnerEdgeOfLauncherVerticalAlignment, |
| 341 0, 0, kPaddingFromBottomOfScreenVerticalAlignment); |
| 342 } else if (params_.shelf_alignment == SHELF_ALIGNMENT_RIGHT) { |
| 343 rect.Inset(0, 0, kPaddingFromInnerEdgeOfLauncherVerticalAlignment, |
| 344 kPaddingFromBottomOfScreenVerticalAlignment); |
| 345 } |
| 346 } |
| 347 } |
| 348 |
272 // TODO(jennyz): May need to add left/right alignment in the following code. | 349 // TODO(jennyz): May need to add left/right alignment in the following code. |
273 if (rect.IsEmpty()) { | 350 if (rect.IsEmpty()) { |
274 rect = gfx::Screen::GetPrimaryDisplay().bounds(); | 351 rect = gfx::Screen::GetPrimaryDisplay().bounds(); |
275 rect = gfx::Rect( | 352 rect = gfx::Rect( |
276 base::i18n::IsRTL() ? kPaddingFromRightEdgeOfScreenBottomAlignment : | 353 base::i18n::IsRTL() ? kPaddingFromRightEdgeOfScreenBottomAlignment : |
277 rect.width() - kPaddingFromRightEdgeOfScreenBottomAlignment, | 354 rect.width() - kPaddingFromRightEdgeOfScreenBottomAlignment, |
278 rect.height() - kPaddingFromBottomOfScreenBottomAlignment, | 355 rect.height() - kPaddingFromBottomOfScreenBottomAlignment, |
279 0, 0); | 356 0, 0); |
280 } | 357 } |
281 return rect; | 358 return rect; |
282 } | 359 } |
283 | 360 |
284 gfx::Rect TrayBubbleView::GetBubbleBounds() { | 361 gfx::Rect TrayBubbleView::GetBubbleBounds() { |
285 // Same as BubbleDelegateView implementation, but don't try mirroring. | 362 // Same as BubbleDelegateView implementation, but don't try mirroring. |
286 return GetBubbleFrameView()->GetUpdatedWindowBounds( | 363 return GetBubbleFrameView()->GetUpdatedWindowBounds( |
287 GetAnchorRect(), GetPreferredSize(), false /*try_mirroring_arrow*/); | 364 GetAnchorRect(), GetPreferredSize(), false /*try_mirroring_arrow*/); |
288 } | 365 } |
289 | 366 |
290 bool TrayBubbleView::CanActivate() const { | 367 bool TrayBubbleView::CanActivate() const { |
291 return can_activate_; | 368 return params_.can_activate; |
| 369 } |
| 370 |
| 371 // Overridden to create BubbleFrameView and set the border to TrayBubbleBorder |
| 372 // (instead of creating a default BubbleBorder and replacing it). |
| 373 views::NonClientFrameView* TrayBubbleView::CreateNonClientFrameView( |
| 374 views::Widget* widget) { |
| 375 TrayBubbleBorder* bubble_border = new TrayBubbleBorder( |
| 376 this, anchor_view(), |
| 377 arrow_location(), params_.arrow_offset, params_.arrow_color); |
| 378 return new views::BubbleFrameView(margins(), bubble_border); |
292 } | 379 } |
293 | 380 |
294 gfx::Size TrayBubbleView::GetPreferredSize() { | 381 gfx::Size TrayBubbleView::GetPreferredSize() { |
295 gfx::Size size = views::BubbleDelegateView::GetPreferredSize(); | 382 gfx::Size size = views::BubbleDelegateView::GetPreferredSize(); |
296 int height = size.height(); | 383 int height = size.height(); |
297 if (max_height_ != 0 && height > max_height_) | 384 if (params_.max_height != 0 && height > params_.max_height) |
298 height = max_height_; | 385 height = params_.max_height; |
299 return gfx::Size(bubble_width_, height); | 386 return gfx::Size(params_.bubble_width, height); |
300 } | 387 } |
301 | 388 |
302 void TrayBubbleView::OnMouseEntered(const views::MouseEvent& event) { | 389 void TrayBubbleView::OnMouseEntered(const views::MouseEvent& event) { |
303 if (host_) | 390 if (host_) |
304 host_->OnMouseEnteredView(); | 391 host_->OnMouseEnteredView(); |
305 } | 392 } |
306 | 393 |
307 void TrayBubbleView::OnMouseExited(const views::MouseEvent& event) { | 394 void TrayBubbleView::OnMouseExited(const views::MouseEvent& event) { |
308 if (host_) | 395 if (host_) |
309 host_->OnMouseExitedView(); | 396 host_->OnMouseExitedView(); |
310 } | 397 } |
311 | 398 |
312 void TrayBubbleView::GetAccessibleState(ui::AccessibleViewState* state) { | 399 void TrayBubbleView::GetAccessibleState(ui::AccessibleViewState* state) { |
313 if (can_activate_) { | 400 if (params_.can_activate) { |
314 state->role = ui::AccessibilityTypes::ROLE_WINDOW; | 401 state->role = ui::AccessibilityTypes::ROLE_WINDOW; |
315 state->name = l10n_util::GetStringUTF16( | 402 state->name = l10n_util::GetStringUTF16( |
316 IDS_ASH_STATUS_TRAY_ACCESSIBLE_NAME); | 403 IDS_ASH_STATUS_TRAY_ACCESSIBLE_NAME); |
317 } | 404 } |
318 } | 405 } |
319 | 406 |
320 void TrayBubbleView::ChildPreferredSizeChanged(View* child) { | 407 void TrayBubbleView::ChildPreferredSizeChanged(View* child) { |
321 SizeToContents(); | 408 SizeToContents(); |
322 } | 409 } |
323 | 410 |
(...skipping 10 matching lines...) Expand all Loading... |
334 TrayBubbleView::Host::Host() | 421 TrayBubbleView::Host::Host() |
335 : widget_(NULL), | 422 : widget_(NULL), |
336 tray_view_(NULL) { | 423 tray_view_(NULL) { |
337 Shell::GetInstance()->AddEnvEventFilter(this); | 424 Shell::GetInstance()->AddEnvEventFilter(this); |
338 } | 425 } |
339 | 426 |
340 TrayBubbleView::Host::~Host() { | 427 TrayBubbleView::Host::~Host() { |
341 Shell::GetInstance()->RemoveEnvEventFilter(this); | 428 Shell::GetInstance()->RemoveEnvEventFilter(this); |
342 } | 429 } |
343 | 430 |
344 void TrayBubbleView::Host::InitializeHost(views::Widget* widget, | 431 void TrayBubbleView::Host::InitializeAndShowBubble(views::Widget* widget, |
345 views::View* tray_view) { | 432 TrayBubbleView* bubble_view, |
| 433 views::View* tray_view) { |
346 widget_ = widget; | 434 widget_ = widget; |
347 tray_view_ = tray_view; | 435 tray_view_ = tray_view; |
| 436 |
| 437 // Must occur after call to BubbleDelegateView::CreateBubble(). |
| 438 bubble_view->SetAlignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); |
| 439 |
| 440 // Setup animation. |
| 441 ash::SetWindowVisibilityAnimationType( |
| 442 widget->GetNativeWindow(), |
| 443 ash::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE); |
| 444 ash::SetWindowVisibilityAnimationTransition( |
| 445 widget->GetNativeWindow(), |
| 446 ash::ANIMATE_BOTH); |
| 447 ash::SetWindowVisibilityAnimationDuration( |
| 448 widget->GetNativeWindow(), |
| 449 base::TimeDelta::FromMilliseconds(kAnimationDurationForPopupMS)); |
| 450 |
| 451 bubble_view->Show(); |
| 452 bubble_view->UpdateBubble(); |
348 } | 453 } |
349 | 454 |
350 bool TrayBubbleView::Host::PreHandleKeyEvent(aura::Window* target, | 455 bool TrayBubbleView::Host::PreHandleKeyEvent(aura::Window* target, |
351 aura::KeyEvent* event) { | 456 aura::KeyEvent* event) { |
352 return false; | 457 return false; |
353 } | 458 } |
354 | 459 |
355 bool TrayBubbleView::Host::PreHandleMouseEvent(aura::Window* target, | 460 bool TrayBubbleView::Host::PreHandleMouseEvent(aura::Window* target, |
356 aura::MouseEvent* event) { | 461 aura::MouseEvent* event) { |
357 if (event->type() == ui::ET_MOUSE_PRESSED) | 462 if (event->type() == ui::ET_MOUSE_PRESSED) |
(...skipping 30 matching lines...) Expand all Loading... |
388 return; | 493 return; |
389 } | 494 } |
390 // Handle clicking outside the bubble and tray. We don't block the event, so | 495 // Handle clicking outside the bubble and tray. We don't block the event, so |
391 // it will also be handled by whatever widget was clicked on. | 496 // it will also be handled by whatever widget was clicked on. |
392 OnClickedOutsideView(); | 497 OnClickedOutsideView(); |
393 } | 498 } |
394 | 499 |
395 | 500 |
396 } // namespace internal | 501 } // namespace internal |
397 } // namespace ash | 502 } // namespace ash |
OLD | NEW |