summaryrefslogtreecommitdiffstats
path: root/ash
diff options
context:
space:
mode:
authorstevenjb@google.com <stevenjb@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-11 18:55:29 +0000
committerstevenjb@google.com <stevenjb@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-11 18:55:29 +0000
commit88a7f3be9f324fece01f29ef1d2f249c646167e1 (patch)
treeaed8cb2fa3619de1abe2d363dbf93d64954dab01 /ash
parent8781235cf8cd5182744de1f50cc1fc26eeb75af9 (diff)
downloadchromium_src-88a7f3be9f324fece01f29ef1d2f249c646167e1.zip
chromium_src-88a7f3be9f324fece01f29ef1d2f249c646167e1.tar.gz
chromium_src-88a7f3be9f324fece01f29ef1d2f249c646167e1.tar.bz2
Move SystemTrayBubbleView to TrayBubbleView in its own file.
There are no non-whitespace code changes, this just moves the code. BUG=124914 TEST=System tray bubble views and borders should look the same. TBR=ben@chromium.org Review URL: https://chromiumcodereview.appspot.com/10532075 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@141447 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r--ash/ash.gyp2
-rw-r--r--ash/system/tray/system_tray_bubble.cc289
-rw-r--r--ash/system/tray/system_tray_bubble.h76
-rw-r--r--ash/system/tray/tray_bubble_view.cc304
-rw-r--r--ash/system/tray/tray_bubble_view.h90
5 files changed, 401 insertions, 360 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp
index af2f46e..8337b4c 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -164,6 +164,8 @@
'system/tray/system_tray_item.h',
'system/tray/tray_background_view.cc',
'system/tray/tray_background_view.h',
+ 'system/tray/tray_bubble_view.cc',
+ 'system/tray/tray_bubble_view.h',
'system/tray/tray_constants.cc',
'system/tray/tray_constants.h',
'system/tray/tray_details_view.cc',
diff --git a/ash/system/tray/system_tray_bubble.cc b/ash/system/tray/system_tray_bubble.cc
index 6a1f70c..ff3430f 100644
--- a/ash/system/tray/system_tray_bubble.cc
+++ b/ash/system/tray/system_tray_bubble.cc
@@ -5,51 +5,25 @@
#include "ash/system/tray/system_tray_bubble.h"
#include "ash/shell.h"
-#include "ash/shell_window_ids.h"
#include "ash/system/tray/system_tray.h"
#include "ash/system/tray/system_tray_delegate.h"
#include "ash/system/tray/system_tray_item.h"
#include "ash/system/tray/tray_constants.h"
-#include "ash/wm/shelf_layout_manager.h"
#include "ash/wm/window_animations.h"
#include "base/message_loop.h"
-#include "grit/ash_strings.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkPaint.h"
-#include "third_party/skia/include/core/SkPath.h"
-#include "third_party/skia/include/effects/SkBlurImageFilter.h"
#include "ui/aura/event.h"
#include "ui/aura/window.h"
-#include "ui/base/accessibility/accessible_view_state.h"
-#include "ui/base/l10n/l10n_util.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/screen.h"
-#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/layout/box_layout.h"
-#include "ui/views/layout/fill_layout.h"
#include "ui/views/view.h"
namespace ash {
namespace {
-const int kShadowThickness = 4;
-
-const int kBottomLineHeight = 1;
-
-const int kSystemTrayBubbleHorizontalInset = 1;
-const int kSystemTrayBubbleVerticalInset = 1;
-
-const int kArrowHeight = 10;
-const int kArrowWidth = 20;
-
-// Inset the arrow a bit from the edge.
-const int kArrowMinOffset = kArrowWidth / 2 + 4;
-
const int kAnimationDurationForPopupMS = 200;
// Normally a detailed view is the same size as the default view. However,
@@ -59,34 +33,6 @@ const int kAnimationDurationForPopupMS = 200;
// detailed view.
const int kDetailedBubbleMaxHeight = kTrayPopupItemHeight * 5;
-const SkColor kShadowColor = SkColorSetARGB(0xff, 0, 0, 0);
-
-void DrawBlurredShadowAroundView(gfx::Canvas* canvas,
- int top,
- int bottom,
- int width,
- const gfx::Insets& inset) {
- SkPath path;
- path.incReserve(4);
- path.moveTo(SkIntToScalar(inset.left() + kShadowThickness),
- SkIntToScalar(top + kShadowThickness + 1));
- path.lineTo(SkIntToScalar(inset.left() + kShadowThickness),
- SkIntToScalar(bottom));
- path.lineTo(SkIntToScalar(width),
- SkIntToScalar(bottom));
- path.lineTo(SkIntToScalar(width),
- SkIntToScalar(top + kShadowThickness + 1));
-
- SkPaint paint;
- paint.setColor(kShadowColor);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
- paint.setStrokeWidth(SkIntToScalar(3));
- paint.setImageFilter(new SkBlurImageFilter(
- SkIntToScalar(3), SkIntToScalar(3)))->unref();
- canvas->sk_canvas()->drawPath(path, paint);
-}
-
// A view with some special behaviour for tray items in the popup:
// - changes background color on hover.
class TrayPopupItemContainer : public views::View {
@@ -147,117 +93,6 @@ class TrayPopupItemContainer : public views::View {
DISALLOW_COPY_AND_ASSIGN(TrayPopupItemContainer);
};
-class SystemTrayBubbleBorder : public views::BubbleBorder {
- public:
- SystemTrayBubbleBorder(views::View* owner,
- views::BubbleBorder::ArrowLocation arrow_location,
- int arrow_offset)
- : views::BubbleBorder(arrow_location,
- views::BubbleBorder::NO_SHADOW),
- owner_(owner),
- tray_arrow_offset_(arrow_offset) {
- set_alignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE);
- }
-
- virtual ~SystemTrayBubbleBorder() {}
-
- private:
- // Overridden from views::BubbleBorder.
- // Override views::BubbleBorder to set the bubble on top of the anchor when
- // it has no arrow.
- virtual gfx::Rect GetBounds(const gfx::Rect& position_relative_to,
- const gfx::Size& contents_size) const OVERRIDE {
- if (arrow_location() != NONE) {
- return views::BubbleBorder::GetBounds(position_relative_to,
- contents_size);
- }
-
- gfx::Size border_size(contents_size);
- gfx::Insets insets;
- GetInsets(&insets);
- border_size.Enlarge(insets.width(), insets.height());
-
- const int kArrowOverlap = 3;
- int x = position_relative_to.x() +
- position_relative_to.width() / 2 - border_size.width() / 2;
- // Position the bubble on top of the anchor.
- int y = position_relative_to.y() +
- kArrowOverlap - border_size.height();
- return gfx::Rect(x, y, border_size.width(), border_size.height());
- }
-
- // Overridden from views::Border.
- virtual void Paint(const views::View& view,
- gfx::Canvas* canvas) const OVERRIDE {
- gfx::Insets inset;
- GetInsets(&inset);
- DrawBlurredShadowAroundView(canvas, 0, owner_->height(), owner_->width(),
- inset);
-
- // Draw the bottom line.
- int y = owner_->height() + 1;
- canvas->FillRect(gfx::Rect(inset.left(), y, owner_->width(),
- kBottomLineHeight), kBorderDarkColor);
-
- if (!Shell::GetInstance()->shelf()->IsVisible() ||
- arrow_location() == views::BubbleBorder::NONE)
- return;
-
- // Draw the arrow after drawing child borders, so that the arrow can cover
- // the its overlap section with child border.
- SkPath path;
- path.incReserve(4);
- if (arrow_location() == views::BubbleBorder::BOTTOM_RIGHT) {
- int tip_x = base::i18n::IsRTL() ? tray_arrow_offset_ :
- owner_->width() - tray_arrow_offset_;
- tip_x = std::min(std::max(kArrowMinOffset, tip_x),
- owner_->width() - kArrowMinOffset);
- int left_base_x = tip_x - kArrowWidth / 2;
- int left_base_y = y;
- int tip_y = left_base_y + kArrowHeight;
- path.moveTo(SkIntToScalar(left_base_x), SkIntToScalar(left_base_y));
- path.lineTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y));
- path.lineTo(SkIntToScalar(left_base_x + kArrowWidth),
- SkIntToScalar(left_base_y));
- } else {
- int tip_y = y - tray_arrow_offset_;
- tip_y = std::min(std::max(kArrowMinOffset, tip_y),
- owner_->height() - kArrowMinOffset);
- int top_base_y = tip_y - kArrowWidth / 2;
- int top_base_x, tip_x;
- if (arrow_location() == views::BubbleBorder::LEFT_BOTTOM) {
- top_base_x = inset.left() + kSystemTrayBubbleHorizontalInset;
- tip_x = top_base_x - kArrowHeight;
- } else {
- DCHECK(arrow_location() == views::BubbleBorder::RIGHT_BOTTOM);
- top_base_x = inset.left() + owner_->width() -
- kSystemTrayBubbleHorizontalInset;
- tip_x = top_base_x + kArrowHeight;
- }
- path.moveTo(SkIntToScalar(top_base_x), SkIntToScalar(top_base_y));
- path.lineTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y));
- path.lineTo(SkIntToScalar(top_base_x),
- SkIntToScalar(top_base_y + kArrowWidth));
- }
-
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- paint.setColor(kHeaderBackgroundColorDark);
- canvas->DrawPath(path, paint);
-
- // Now draw the arrow border.
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setColor(kBorderDarkColor);
- canvas->DrawPath(path, paint);
-
- }
-
- views::View* owner_;
- const int tray_arrow_offset_;
-
- DISALLOW_COPY_AND_ASSIGN(SystemTrayBubbleBorder);
-};
-
// Implicit animation observer that deletes itself and the layer at the end of
// the animation.
class AnimationObserverDeleteLayer : public ui::ImplicitAnimationObserver {
@@ -283,128 +118,6 @@ class AnimationObserverDeleteLayer : public ui::ImplicitAnimationObserver {
namespace internal {
-// SystemTrayBubbleView
-
-SystemTrayBubbleView::SystemTrayBubbleView(
- views::View* anchor,
- views::BubbleBorder::ArrowLocation arrow_location,
- Host* host,
- bool can_activate,
- int bubble_width)
- : views::BubbleDelegateView(anchor, arrow_location),
- host_(host),
- can_activate_(can_activate),
- max_height_(0),
- bubble_width_(bubble_width) {
- set_margin(0);
- set_parent_window(Shell::GetContainer(
- anchor->GetWidget()->GetNativeWindow()->GetRootWindow(),
- internal::kShellWindowId_SettingBubbleContainer));
- set_notify_enter_exit_on_child(true);
- SetPaintToLayer(true);
- SetFillsBoundsOpaquely(true);
-}
-
-SystemTrayBubbleView::~SystemTrayBubbleView() {
- // Inform host items (models) that their views are being destroyed.
- if (host_)
- host_->BubbleViewDestroyed();
-}
-
-void SystemTrayBubbleView::SetBubbleBorder(int arrow_offset) {
- DCHECK(GetWidget());
- SystemTrayBubbleBorder* bubble_border = new SystemTrayBubbleBorder(
- this, arrow_location(), arrow_offset);
- GetBubbleFrameView()->SetBubbleBorder(bubble_border);
- // Recalculate size with new border.
- SizeToContents();
-}
-
-void SystemTrayBubbleView::UpdateAnchor() {
- SizeToContents();
- GetWidget()->GetRootView()->SchedulePaint();
-}
-
-void SystemTrayBubbleView::SetMaxHeight(int height) {
- max_height_ = height;
- if (GetWidget())
- SizeToContents();
-}
-
-void SystemTrayBubbleView::Init() {
- views::BoxLayout* layout =
- new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0);
- layout->set_spread_blank_space(true);
- SetLayoutManager(layout);
- set_background(NULL);
-}
-
-gfx::Rect SystemTrayBubbleView::GetAnchorRect() {
- gfx::Rect rect;
- if (host_)
- rect = host_->GetAnchorRect();
- // TODO(jennyz): May need to add left/right alignment in the following code.
- if (rect.IsEmpty()) {
- rect = gfx::Screen::GetPrimaryMonitor().bounds();
- rect = gfx::Rect(
- base::i18n::IsRTL() ? kPaddingFromRightEdgeOfScreenBottomAlignment :
- rect.width() - kPaddingFromRightEdgeOfScreenBottomAlignment,
- rect.height() - kPaddingFromBottomOfScreenBottomAlignment,
- 0, 0);
- }
- return rect;
-}
-
-gfx::Rect SystemTrayBubbleView::GetBubbleBounds() {
- // Same as BubbleDelegateView implementation, but don't try mirroring.
- return GetBubbleFrameView()->GetUpdatedWindowBounds(
- GetAnchorRect(), GetPreferredSize(), false /*try_mirroring_arrow*/);
-}
-
-bool SystemTrayBubbleView::CanActivate() const {
- return can_activate_;
-}
-
-gfx::Size SystemTrayBubbleView::GetPreferredSize() {
- gfx::Size size = views::BubbleDelegateView::GetPreferredSize();
- int height = size.height();
- if (max_height_ != 0 && height > max_height_)
- height = max_height_;
- return gfx::Size(bubble_width_, height);
-}
-
-void SystemTrayBubbleView::OnMouseEntered(const views::MouseEvent& event) {
- if (host_)
- host_->OnMouseEnteredView();
-}
-
-void SystemTrayBubbleView::OnMouseExited(const views::MouseEvent& event) {
- if (host_)
- host_->OnMouseExitedView();
-}
-
-void SystemTrayBubbleView::GetAccessibleState(ui::AccessibleViewState* state) {
- if (can_activate_) {
- state->role = ui::AccessibilityTypes::ROLE_WINDOW;
- state->name = l10n_util::GetStringUTF16(
- IDS_ASH_STATUS_TRAY_ACCESSIBLE_NAME);
- }
-}
-
-void SystemTrayBubbleView::ChildPreferredSizeChanged(View* child) {
- SizeToContents();
-}
-
-void SystemTrayBubbleView::ViewHierarchyChanged(bool is_add,
- views::View* parent,
- views::View* child) {
- if (is_add && child == this) {
- parent->SetPaintToLayer(true);
- parent->SetFillsBoundsOpaquely(true);
- parent->layer()->SetMasksToBounds(true);
- }
-}
-
// SystemTrayBubble::InitParams
SystemTrayBubble::InitParams::InitParams(
SystemTrayBubble::AnchorType anchor_type,
@@ -545,7 +258,7 @@ void SystemTrayBubble::InitView(const InitParams& init_params) {
} else {
arrow_location = views::BubbleBorder::NONE;
}
- bubble_view_ = new SystemTrayBubbleView(
+ bubble_view_ = new TrayBubbleView(
init_params.anchor, arrow_location,
this, init_params.can_activate, kTrayPopupWidth);
if (bubble_type_ == BUBBLE_TYPE_NOTIFICATION)
diff --git a/ash/system/tray/system_tray_bubble.h b/ash/system/tray/system_tray_bubble.h
index 2ef75d2..bdc138e 100644
--- a/ash/system/tray/system_tray_bubble.h
+++ b/ash/system/tray/system_tray_bubble.h
@@ -6,12 +6,12 @@
#define ASH_SYSTEM_TRAY_SYSTEM_TRAY_BUBBLE_H_
#pragma once
+#include "ash/system/tray/tray_bubble_view.h"
#include "ash/system/user/login_status.h"
#include "ash/wm/shelf_auto_hide_behavior.h"
#include "base/base_export.h"
#include "base/timer.h"
#include "ui/aura/event_filter.h"
-#include "ui/views/bubble/bubble_delegate.h"
#include "ui/views/widget/widget.h"
#include <vector>
@@ -27,77 +27,9 @@ class SystemTrayItem;
namespace internal {
-class SystemTrayBubble;
-
-class SystemTrayBubbleView : public views::BubbleDelegateView {
- public:
- class Host {
- public:
- Host() {}
- virtual ~Host() {}
-
- virtual void BubbleViewDestroyed() = 0;
- virtual gfx::Rect GetAnchorRect() const = 0;
- virtual void OnMouseEnteredView() = 0;
- virtual void OnMouseExitedView() = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Host);
- };
-
- SystemTrayBubbleView(views::View* anchor,
- views::BubbleBorder::ArrowLocation arrow_location,
- Host* host,
- bool can_activate,
- int bubble_width);
- virtual ~SystemTrayBubbleView();
-
- // Creates a bubble border with the specified arrow offset.
- void SetBubbleBorder(int arrow_offset);
-
- // Called whenever the bubble anchor location may have moved.
- void UpdateAnchor();
-
- // Sets the maximum bubble height and resizes the bubble.
- void SetMaxHeight(int height);
-
- // Called when the host is destroyed.
- void reset_host() { host_ = NULL; }
-
- // Overridden from views::WidgetDelegate.
- virtual bool CanActivate() const OVERRIDE;
-
- // Overridden from views::BubbleDelegateView.
- virtual gfx::Rect GetAnchorRect() OVERRIDE;
-
- // Overridden from views::View.
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual void OnMouseEntered(const views::MouseEvent& event) OVERRIDE;
- virtual void OnMouseExited(const views::MouseEvent& event) OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
-
- protected:
- // Overridden from views::BubbleDelegateView.
- virtual void Init() OVERRIDE;
- virtual gfx::Rect GetBubbleBounds() OVERRIDE;
-
- // Overridden from views::View.
- virtual void ChildPreferredSizeChanged(View* child) OVERRIDE;
- virtual void ViewHierarchyChanged(bool is_add,
- views::View* parent,
- views::View* child) OVERRIDE;
-
- Host* host_;
- bool can_activate_;
- int max_height_;
- int bubble_width_;
-
- DISALLOW_COPY_AND_ASSIGN(SystemTrayBubbleView);
-};
-
class SystemTrayBubble : public aura::EventFilter,
public views::Widget::Observer,
- public SystemTrayBubbleView::Host {
+ public TrayBubbleView::Host {
public:
enum BubbleType {
BUBBLE_TYPE_DEFAULT,
@@ -141,7 +73,7 @@ class SystemTrayBubble : public aura::EventFilter,
virtual void OnMouseExitedView() OVERRIDE;
BubbleType bubble_type() const { return bubble_type_; }
- SystemTrayBubbleView* bubble_view() const { return bubble_view_; }
+ TrayBubbleView* bubble_view() const { return bubble_view_; }
void DestroyItemViews();
void StartAutoCloseTimer(int seconds);
@@ -171,7 +103,7 @@ class SystemTrayBubble : public aura::EventFilter,
virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE;
ash::SystemTray* tray_;
- SystemTrayBubbleView* bubble_view_;
+ TrayBubbleView* bubble_view_;
views::Widget* bubble_widget_;
std::vector<ash::SystemTrayItem*> items_;
BubbleType bubble_type_;
diff --git a/ash/system/tray/tray_bubble_view.cc b/ash/system/tray/tray_bubble_view.cc
new file mode 100644
index 0000000..cbb074b
--- /dev/null
+++ b/ash/system/tray/tray_bubble_view.cc
@@ -0,0 +1,304 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/system/tray/tray_bubble_view.h"
+
+#include "ash/shell.h"
+#include "ash/shell_window_ids.h"
+#include "ash/system/tray/tray_constants.h"
+#include "ash/wm/shelf_layout_manager.h"
+#include "grit/ash_strings.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkPath.h"
+#include "third_party/skia/include/effects/SkBlurImageFilter.h"
+#include "ui/aura/window.h"
+#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/screen.h"
+#include "ui/views/bubble/bubble_frame_view.h"
+#include "ui/views/layout/box_layout.h"
+
+namespace ash {
+
+namespace {
+
+const int kShadowThickness = 4;
+const int kBottomLineHeight = 1;
+const int kSystemTrayBubbleHorizontalInset = 1;
+const int kSystemTrayBubbleVerticalInset = 1;
+
+const int kArrowHeight = 10;
+const int kArrowWidth = 20;
+
+// Inset the arrow a bit from the edge.
+const int kArrowMinOffset = kArrowWidth / 2 + 4;
+
+const SkColor kShadowColor = SkColorSetARGB(0xff, 0, 0, 0);
+
+void DrawBlurredShadowAroundView(gfx::Canvas* canvas,
+ int top,
+ int bottom,
+ int width,
+ const gfx::Insets& inset) {
+ SkPath path;
+ path.incReserve(4);
+ path.moveTo(SkIntToScalar(inset.left() + kShadowThickness),
+ SkIntToScalar(top + kShadowThickness + 1));
+ path.lineTo(SkIntToScalar(inset.left() + kShadowThickness),
+ SkIntToScalar(bottom));
+ path.lineTo(SkIntToScalar(width),
+ SkIntToScalar(bottom));
+ path.lineTo(SkIntToScalar(width),
+ SkIntToScalar(top + kShadowThickness + 1));
+
+ SkPaint paint;
+ paint.setColor(kShadowColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
+ paint.setStrokeWidth(SkIntToScalar(3));
+ paint.setImageFilter(new SkBlurImageFilter(
+ SkIntToScalar(3), SkIntToScalar(3)))->unref();
+ canvas->sk_canvas()->drawPath(path, paint);
+}
+
+class TrayBubbleBorder : public views::BubbleBorder {
+ public:
+ TrayBubbleBorder(views::View* owner,
+ views::BubbleBorder::ArrowLocation arrow_location,
+ int arrow_offset)
+ : views::BubbleBorder(arrow_location,
+ views::BubbleBorder::NO_SHADOW),
+ owner_(owner),
+ tray_arrow_offset_(arrow_offset) {
+ set_alignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE);
+ }
+
+ virtual ~TrayBubbleBorder() {}
+
+ private:
+ // Overridden from views::BubbleBorder.
+ // Override views::BubbleBorder to set the bubble on top of the anchor when
+ // it has no arrow.
+ virtual gfx::Rect GetBounds(const gfx::Rect& position_relative_to,
+ const gfx::Size& contents_size) const OVERRIDE {
+ if (arrow_location() != NONE) {
+ return views::BubbleBorder::GetBounds(position_relative_to,
+ contents_size);
+ }
+
+ gfx::Size border_size(contents_size);
+ gfx::Insets insets;
+ GetInsets(&insets);
+ border_size.Enlarge(insets.width(), insets.height());
+
+ const int kArrowOverlap = 3;
+ int x = position_relative_to.x() +
+ position_relative_to.width() / 2 - border_size.width() / 2;
+ // Position the bubble on top of the anchor.
+ int y = position_relative_to.y() +
+ kArrowOverlap - border_size.height();
+ return gfx::Rect(x, y, border_size.width(), border_size.height());
+ }
+
+ // Overridden from views::Border.
+ virtual void Paint(const views::View& view,
+ gfx::Canvas* canvas) const OVERRIDE {
+ gfx::Insets inset;
+ GetInsets(&inset);
+ DrawBlurredShadowAroundView(
+ canvas, 0, owner_->height(), owner_->width(), inset);
+
+ // Draw the bottom line.
+ int y = owner_->height() + 1;
+ canvas->FillRect(gfx::Rect(inset.left(), y, owner_->width(),
+ kBottomLineHeight), kBorderDarkColor);
+
+ if (!Shell::GetInstance()->shelf()->IsVisible() ||
+ arrow_location() == views::BubbleBorder::NONE)
+ return;
+
+ // Draw the arrow after drawing child borders, so that the arrow can cover
+ // the its overlap section with child border.
+ SkPath path;
+ path.incReserve(4);
+ if (arrow_location() == views::BubbleBorder::BOTTOM_RIGHT) {
+ int tip_x = base::i18n::IsRTL() ? tray_arrow_offset_ :
+ owner_->width() - tray_arrow_offset_;
+ tip_x = std::min(std::max(kArrowMinOffset, tip_x),
+ owner_->width() - kArrowMinOffset);
+ int left_base_x = tip_x - kArrowWidth / 2;
+ int left_base_y = y;
+ int tip_y = left_base_y + kArrowHeight;
+ path.moveTo(SkIntToScalar(left_base_x), SkIntToScalar(left_base_y));
+ path.lineTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y));
+ path.lineTo(SkIntToScalar(left_base_x + kArrowWidth),
+ SkIntToScalar(left_base_y));
+ } else {
+ int tip_y = y - tray_arrow_offset_;
+ tip_y = std::min(std::max(kArrowMinOffset, tip_y),
+ owner_->height() - kArrowMinOffset);
+ int top_base_y = tip_y - kArrowWidth / 2;
+ int top_base_x, tip_x;
+ if (arrow_location() == views::BubbleBorder::LEFT_BOTTOM) {
+ top_base_x = inset.left() + kSystemTrayBubbleHorizontalInset;
+ tip_x = top_base_x - kArrowHeight;
+ } else {
+ DCHECK(arrow_location() == views::BubbleBorder::RIGHT_BOTTOM);
+ top_base_x = inset.left() + owner_->width() -
+ kSystemTrayBubbleHorizontalInset;
+ tip_x = top_base_x + kArrowHeight;
+ }
+ path.moveTo(SkIntToScalar(top_base_x), SkIntToScalar(top_base_y));
+ path.lineTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y));
+ path.lineTo(SkIntToScalar(top_base_x),
+ SkIntToScalar(top_base_y + kArrowWidth));
+ }
+
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(kHeaderBackgroundColorDark);
+ canvas->DrawPath(path, paint);
+
+ // Now draw the arrow border.
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setColor(kBorderDarkColor);
+ canvas->DrawPath(path, paint);
+
+ }
+
+ views::View* owner_;
+ const int tray_arrow_offset_;
+
+ DISALLOW_COPY_AND_ASSIGN(TrayBubbleBorder);
+};
+
+} // namespace
+
+namespace internal {
+
+TrayBubbleView::TrayBubbleView(
+ views::View* anchor,
+ views::BubbleBorder::ArrowLocation arrow_location,
+ Host* host,
+ bool can_activate,
+ int bubble_width)
+ : views::BubbleDelegateView(anchor, arrow_location),
+ host_(host),
+ can_activate_(can_activate),
+ max_height_(0),
+ bubble_width_(bubble_width) {
+ set_margin(0);
+ set_parent_window(Shell::GetContainer(
+ anchor->GetWidget()->GetNativeWindow()->GetRootWindow(),
+ internal::kShellWindowId_SettingBubbleContainer));
+ set_notify_enter_exit_on_child(true);
+ SetPaintToLayer(true);
+ SetFillsBoundsOpaquely(true);
+}
+
+TrayBubbleView::~TrayBubbleView() {
+ // Inform host items (models) that their views are being destroyed.
+ if (host_)
+ host_->BubbleViewDestroyed();
+}
+
+void TrayBubbleView::SetBubbleBorder(int arrow_offset) {
+ DCHECK(GetWidget());
+ TrayBubbleBorder* bubble_border = new TrayBubbleBorder(
+ this, arrow_location(), arrow_offset);
+ GetBubbleFrameView()->SetBubbleBorder(bubble_border);
+ // Recalculate size with new border.
+ SizeToContents();
+}
+
+void TrayBubbleView::UpdateAnchor() {
+ SizeToContents();
+ GetWidget()->GetRootView()->SchedulePaint();
+}
+
+void TrayBubbleView::SetMaxHeight(int height) {
+ max_height_ = height;
+ if (GetWidget())
+ SizeToContents();
+}
+
+void TrayBubbleView::Init() {
+ views::BoxLayout* layout =
+ new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0);
+ layout->set_spread_blank_space(true);
+ SetLayoutManager(layout);
+ set_background(NULL);
+}
+
+gfx::Rect TrayBubbleView::GetAnchorRect() {
+ gfx::Rect rect;
+ if (host_)
+ rect = host_->GetAnchorRect();
+ // TODO(jennyz): May need to add left/right alignment in the following code.
+ if (rect.IsEmpty()) {
+ rect = gfx::Screen::GetPrimaryMonitor().bounds();
+ rect = gfx::Rect(
+ base::i18n::IsRTL() ? kPaddingFromRightEdgeOfScreenBottomAlignment :
+ rect.width() - kPaddingFromRightEdgeOfScreenBottomAlignment,
+ rect.height() - kPaddingFromBottomOfScreenBottomAlignment,
+ 0, 0);
+ }
+ return rect;
+}
+
+gfx::Rect TrayBubbleView::GetBubbleBounds() {
+ // Same as BubbleDelegateView implementation, but don't try mirroring.
+ return GetBubbleFrameView()->GetUpdatedWindowBounds(
+ GetAnchorRect(), GetPreferredSize(), false /*try_mirroring_arrow*/);
+}
+
+bool TrayBubbleView::CanActivate() const {
+ return can_activate_;
+}
+
+gfx::Size TrayBubbleView::GetPreferredSize() {
+ gfx::Size size = views::BubbleDelegateView::GetPreferredSize();
+ int height = size.height();
+ if (max_height_ != 0 && height > max_height_)
+ height = max_height_;
+ return gfx::Size(bubble_width_, height);
+}
+
+void TrayBubbleView::OnMouseEntered(const views::MouseEvent& event) {
+ if (host_)
+ host_->OnMouseEnteredView();
+}
+
+void TrayBubbleView::OnMouseExited(const views::MouseEvent& event) {
+ if (host_)
+ host_->OnMouseExitedView();
+}
+
+void TrayBubbleView::GetAccessibleState(ui::AccessibleViewState* state) {
+ if (can_activate_) {
+ state->role = ui::AccessibilityTypes::ROLE_WINDOW;
+ state->name = l10n_util::GetStringUTF16(
+ IDS_ASH_STATUS_TRAY_ACCESSIBLE_NAME);
+ }
+}
+
+void TrayBubbleView::ChildPreferredSizeChanged(View* child) {
+ SizeToContents();
+}
+
+void TrayBubbleView::ViewHierarchyChanged(bool is_add,
+ views::View* parent,
+ views::View* child) {
+ if (is_add && child == this) {
+ parent->SetPaintToLayer(true);
+ parent->SetFillsBoundsOpaquely(true);
+ parent->layer()->SetMasksToBounds(true);
+ }
+}
+
+} // namespace internal
+} // namespace ash
diff --git a/ash/system/tray/tray_bubble_view.h b/ash/system/tray/tray_bubble_view.h
new file mode 100644
index 0000000..1d9008f
--- /dev/null
+++ b/ash/system/tray/tray_bubble_view.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_SYSTEM_TRAY_TRAY_BUBBLE_VIEW_H_
+#define ASH_SYSTEM_TRAY_TRAY_BUBBLE_VIEW_H_
+#pragma once
+
+#include "ui/views/bubble/bubble_delegate.h"
+
+namespace views {
+class View;
+}
+
+namespace ash {
+namespace internal {
+
+// Specialized bubble view for status area tray bubbles.
+// Mostly this handles custom anchor location and arrow and border rendering.
+class TrayBubbleView : public views::BubbleDelegateView {
+ public:
+ class Host {
+ public:
+ Host() {}
+ virtual ~Host() {}
+
+ virtual void BubbleViewDestroyed() = 0;
+ virtual gfx::Rect GetAnchorRect() const = 0;
+ virtual void OnMouseEnteredView() = 0;
+ virtual void OnMouseExitedView() = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Host);
+ };
+
+ TrayBubbleView(views::View* anchor,
+ views::BubbleBorder::ArrowLocation arrow_location,
+ Host* host,
+ bool can_activate,
+ int bubble_width);
+ virtual ~TrayBubbleView();
+
+ // Creates a bubble border with the specified arrow offset.
+ void SetBubbleBorder(int arrow_offset);
+
+ // Called whenever the bubble anchor location may have moved.
+ void UpdateAnchor();
+
+ // Sets the maximum bubble height and resizes the bubble.
+ void SetMaxHeight(int height);
+
+ // Called when the host is destroyed.
+ void reset_host() { host_ = NULL; }
+
+ // Overridden from views::WidgetDelegate.
+ virtual bool CanActivate() const OVERRIDE;
+
+ // Overridden from views::BubbleDelegateView.
+ virtual gfx::Rect GetAnchorRect() OVERRIDE;
+
+ // Overridden from views::View.
+ virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual void OnMouseEntered(const views::MouseEvent& event) OVERRIDE;
+ virtual void OnMouseExited(const views::MouseEvent& event) OVERRIDE;
+ virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+
+ protected:
+ // Overridden from views::BubbleDelegateView.
+ virtual void Init() OVERRIDE;
+ virtual gfx::Rect GetBubbleBounds() OVERRIDE;
+
+ // Overridden from views::View.
+ virtual void ChildPreferredSizeChanged(View* child) OVERRIDE;
+ virtual void ViewHierarchyChanged(bool is_add,
+ views::View* parent,
+ views::View* child) OVERRIDE;
+
+ private:
+ Host* host_;
+ bool can_activate_;
+ int max_height_;
+ int bubble_width_;
+
+ DISALLOW_COPY_AND_ASSIGN(TrayBubbleView);
+};
+
+} // namespace internal
+} // namespace ash
+
+#endif // ASH_SYSTEM_TRAY_TRAY_BUBBLE_VIEW_H_