| 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 |