Index: ash/system/tray/tray_bubble_view.cc |
diff --git a/ash/system/tray/tray_bubble_view.cc b/ash/system/tray/tray_bubble_view.cc |
index 1b934d4c399a20b36015d78173dd7c1a4e0bf1f4..345d2700d1706110929e5249a24bf06b7c8bdb00 100644 |
--- a/ash/system/tray/tray_bubble_view.cc |
+++ b/ash/system/tray/tray_bubble_view.cc |
@@ -8,6 +8,7 @@ |
#include "ash/shell_window_ids.h" |
#include "ash/system/tray/tray_constants.h" |
#include "ash/wm/shelf_layout_manager.h" |
+#include "ash/wm/window_animations.h" |
#include "grit/ash_strings.h" |
#include "third_party/skia/include/core/SkCanvas.h" |
#include "third_party/skia/include/core/SkColor.h" |
@@ -37,10 +38,13 @@ const int kArrowHeight = 10; |
const int kArrowWidth = 20; |
// Inset the arrow a bit from the edge. |
-const int kArrowMinOffset = kArrowWidth / 2 + 4; |
+const int kArrowEdgeMargin = 12; |
+const int kArrowMinOffset = kArrowWidth / 2 + kArrowEdgeMargin; |
const SkColor kShadowColor = SkColorSetARGB(0xff, 0, 0, 0); |
+const int kAnimationDurationForPopupMS = 200; |
+ |
void DrawBlurredShadowAroundView(gfx::Canvas* canvas, |
int top, |
int bottom, |
@@ -79,20 +83,15 @@ class TrayBubbleBorder : public views::BubbleBorder { |
anchor_(anchor), |
tray_arrow_offset_(arrow_offset) { |
set_alignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); |
+ // Normally all rendering is mirrored for RTL. This doesn't work correctly |
+ // with status area bubbles, and would make Paint much more complex. |
+ // Instead, set rtl_mirrored_ to false so that GetInsets() returns |
+ // the unmirrored insets. |
+ set_rtl_mirrored(false); |
} |
virtual ~TrayBubbleBorder() {} |
- private: |
- views::Background* FindAppropriateBackground(views::View* view, |
- const gfx::Point& point) const { |
- views::Background* background = NULL; |
- views::View* target = view->GetEventHandlerForPoint(point); |
- for (; target && !background; target = target->parent()) |
- background = target->background(); |
- return background; |
- } |
- |
// Overridden from views::BubbleBorder. |
// Override views::BubbleBorder to set the bubble on top of the anchor when |
// it has no arrow. |
@@ -121,7 +120,8 @@ class TrayBubbleBorder : public views::BubbleBorder { |
virtual void Paint(const views::View& view, |
gfx::Canvas* canvas) const OVERRIDE { |
gfx::Insets inset; |
- GetInsets(&inset); |
+ // Get the unmirrored insets for the arrow location. |
+ GetInsetsForArrowLocation(&inset, arrow_location()); |
DrawBlurredShadowAroundView( |
canvas, 0, owner_->height(), owner_->width(), inset); |
@@ -142,17 +142,23 @@ class TrayBubbleBorder : public views::BubbleBorder { |
path.incReserve(4); |
if (arrow_location() == views::BubbleBorder::BOTTOM_RIGHT || |
arrow_location() == views::BubbleBorder::BOTTOM_LEFT) { |
- // Do not let the arrow too close to the edge of the bubble and |
- // and the edge of the anchor. |
- int tip_x = base::i18n::IsRTL() ? |
- std::min(std::max(tray_arrow_offset_, kArrowMinOffset), |
- std::min(owner_->width(), anchor_->width()) |
- - kArrowMinOffset) : |
- std::min(std::max(owner_->width() - tray_arrow_offset_, |
- owner_->width() - |
- std::min(owner_->width(), anchor_->width()) + |
- kArrowMinOffset), |
- owner_->width() - kArrowMinOffset); |
+ // Note: tray_arrow_offset_ is relative to the anchor widget. |
+ int tip_x; |
+ if (tray_arrow_offset_ == |
+ internal::TrayBubbleView::InitParams::kArrowDefaultOffset) { |
+ if (arrow_location() == views::BubbleBorder::BOTTOM_LEFT) |
+ tip_x = kArrowMinOffset; |
+ else |
+ tip_x = owner_->width() - kArrowMinOffset; |
+ } else { |
+ gfx::Point pt(tray_arrow_offset_, 0); |
+ views::View::ConvertPointToScreen( |
+ anchor_->GetWidget()->GetRootView(), &pt); |
+ views::View::ConvertPointFromScreen( |
+ owner_->GetWidget()->GetRootView(), &pt); |
+ tip_x = std::min(pt.x(), owner_->width() - kArrowMinOffset); |
+ tip_x = std::max(tip_x, kArrowMinOffset); |
+ } |
int left_base_x = tip_x - kArrowWidth / 2; |
int left_base_y = y; |
int tip_y = left_base_y + kArrowHeight; |
@@ -162,9 +168,20 @@ class TrayBubbleBorder : public views::BubbleBorder { |
SkIntToScalar(left_base_y)); |
arrow_reference.SetPoint(tip_x, left_base_y - kArrowHeight); |
} else { |
- int tip_y = y - tray_arrow_offset_; |
- tip_y = std::min(std::max(kArrowMinOffset, tip_y), |
- owner_->height() - kArrowMinOffset); |
+ int tip_y; |
+ if (tray_arrow_offset_ == |
+ internal::TrayBubbleView::InitParams::kArrowDefaultOffset) { |
+ tip_y = owner_->height() - kArrowMinOffset; |
+ } else { |
+ int pty = y - tray_arrow_offset_; |
+ gfx::Point pt(0, pty); |
+ views::View::ConvertPointToScreen( |
+ anchor_->GetWidget()->GetRootView(), &pt); |
+ views::View::ConvertPointFromScreen( |
+ owner_->GetWidget()->GetRootView(), &pt); |
+ tip_y = std::min(pt.y(), owner_->height() - kArrowMinOffset); |
+ tip_y = std::max(tip_y, kArrowMinOffset); |
+ } |
int top_base_y = tip_y - kArrowWidth / 2; |
int top_base_x, tip_x; |
if (arrow_location() == views::BubbleBorder::LEFT_BOTTOM) { |
@@ -199,6 +216,16 @@ class TrayBubbleBorder : public views::BubbleBorder { |
} |
+ private: |
+ views::Background* FindAppropriateBackground(views::View* view, |
+ const gfx::Point& point) const { |
+ views::Background* background = NULL; |
+ views::View* target = view->GetEventHandlerForPoint(point); |
+ for (; target && !background; target = target->parent()) |
+ background = target->background(); |
+ return background; |
+ } |
+ |
views::View* owner_; |
views::View* anchor_; |
const int tray_arrow_offset_; |
@@ -210,17 +237,49 @@ class TrayBubbleBorder : public views::BubbleBorder { |
namespace internal { |
+// static |
+const int TrayBubbleView::InitParams::kArrowDefaultOffset = -1; |
+ |
+TrayBubbleView::InitParams::InitParams(AnchorType anchor_type, |
+ ShelfAlignment shelf_alignment) |
+ : anchor_type(anchor_type), |
+ shelf_alignment(shelf_alignment), |
+ bubble_width(kTrayPopupWidth), |
+ max_height(0), |
+ can_activate(false), |
+ arrow_offset(kArrowDefaultOffset) { |
+} |
+ |
+TrayBubbleView* TrayBubbleView::Create(views::View* anchor, |
+ Host* host, |
+ const InitParams& init_params) { |
+ // Set arrow_location here so that it can be passed correctly to the |
+ // BubbleView constructor. |
+ views::BubbleBorder::ArrowLocation arrow_location; |
+ if (init_params.anchor_type == ANCHOR_TYPE_TRAY) { |
+ if (init_params.shelf_alignment == SHELF_ALIGNMENT_BOTTOM) { |
+ arrow_location = base::i18n::IsRTL() ? |
+ views::BubbleBorder::BOTTOM_LEFT : views::BubbleBorder::BOTTOM_RIGHT; |
+ } else if (init_params.shelf_alignment == SHELF_ALIGNMENT_LEFT) { |
+ arrow_location = views::BubbleBorder::LEFT_BOTTOM; |
+ } else { |
+ arrow_location = views::BubbleBorder::RIGHT_BOTTOM; |
+ } |
+ } else { |
+ arrow_location = views::BubbleBorder::NONE; |
+ } |
+ |
+ return new TrayBubbleView(init_params, arrow_location, anchor, host); |
+} |
+ |
TrayBubbleView::TrayBubbleView( |
- views::View* anchor, |
+ const InitParams& init_params, |
views::BubbleBorder::ArrowLocation arrow_location, |
- Host* host, |
- bool can_activate, |
- int bubble_width) |
+ views::View* anchor, |
+ Host* host) |
: views::BubbleDelegateView(anchor, arrow_location), |
- host_(host), |
- can_activate_(can_activate), |
- max_height_(0), |
- bubble_width_(bubble_width) { |
+ params_(init_params), |
+ host_(host) { |
set_margins(gfx::Insets()); |
set_parent_window(Shell::GetContainer( |
anchor->GetWidget()->GetNativeWindow()->GetRootWindow(), |
@@ -236,22 +295,13 @@ TrayBubbleView::~TrayBubbleView() { |
host_->BubbleViewDestroyed(); |
} |
-void TrayBubbleView::SetBubbleBorder(int arrow_offset) { |
- DCHECK(GetWidget()); |
- TrayBubbleBorder* bubble_border = new TrayBubbleBorder( |
- this, anchor_view(), 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; |
+ params_.max_height = height; |
if (GetWidget()) |
SizeToContents(); |
} |
@@ -266,8 +316,36 @@ void TrayBubbleView::Init() { |
gfx::Rect TrayBubbleView::GetAnchorRect() { |
gfx::Rect rect; |
- if (host_) |
- rect = host_->GetAnchorRect(); |
+ |
+ if (anchor_widget()->IsVisible()) { |
+ rect = anchor_widget()->GetWindowBoundsInScreen(); |
+ if (params_.anchor_type == ANCHOR_TYPE_TRAY) { |
+ if (params_.shelf_alignment == SHELF_ALIGNMENT_BOTTOM) { |
+ bool rtl = base::i18n::IsRTL(); |
+ rect.Inset( |
+ rtl ? kPaddingFromRightEdgeOfScreenBottomAlignment : 0, |
+ 0, |
+ rtl ? 0 : kPaddingFromRightEdgeOfScreenBottomAlignment, |
+ kPaddingFromBottomOfScreenBottomAlignment); |
+ } else if (params_.shelf_alignment == SHELF_ALIGNMENT_LEFT) { |
+ rect.Inset(0, 0, kPaddingFromInnerEdgeOfLauncherVerticalAlignment, |
+ kPaddingFromBottomOfScreenVerticalAlignment); |
+ } else { |
+ rect.Inset(kPaddingFromInnerEdgeOfLauncherVerticalAlignment, |
+ 0, 0, kPaddingFromBottomOfScreenVerticalAlignment); |
+ } |
+ } else if (params_.anchor_type == ANCHOR_TYPE_BUBBLE) { |
+ // Invert the offsets to align with the bubble below. |
+ if (params_.shelf_alignment == SHELF_ALIGNMENT_LEFT) { |
+ rect.Inset(kPaddingFromInnerEdgeOfLauncherVerticalAlignment, |
+ 0, 0, kPaddingFromBottomOfScreenVerticalAlignment); |
+ } else if (params_.shelf_alignment == SHELF_ALIGNMENT_RIGHT) { |
+ rect.Inset(0, 0, kPaddingFromInnerEdgeOfLauncherVerticalAlignment, |
+ kPaddingFromBottomOfScreenVerticalAlignment); |
+ } |
+ } |
+ } |
+ |
// TODO(jennyz): May need to add left/right alignment in the following code. |
if (rect.IsEmpty()) { |
rect = gfx::Screen::GetPrimaryDisplay().bounds(); |
@@ -287,15 +365,27 @@ gfx::Rect TrayBubbleView::GetBubbleBounds() { |
} |
bool TrayBubbleView::CanActivate() const { |
- return can_activate_; |
+ return params_.can_activate; |
+} |
+ |
+// Overridden to create BubbleFrameView and set the border to TrayBubbleBorder |
+// (instead of creating a default BubbleBorder and replacing it). |
+views::NonClientFrameView* TrayBubbleView::CreateNonClientFrameView( |
+ views::Widget* widget) { |
+ views::BubbleFrameView* bubble_frame_view = |
msw
2012/07/23 22:20:49
Instead of changing the BubbleFrameView constructi
stevenjb
2012/07/23 23:32:06
The problem was that first a BubbleBorder() was ge
msw
2012/07/24 00:32:44
Ah, that's fair. Consider passing a BubbleBorder i
stevenjb
2012/07/26 23:48:30
Done.
|
+ new views::BubbleFrameView(margins()); |
+ TrayBubbleBorder* bubble_border = new TrayBubbleBorder( |
+ this, anchor_view(), arrow_location(), params_.arrow_offset); |
+ bubble_frame_view->SetBubbleBorder(bubble_border); |
+ return bubble_frame_view; |
} |
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); |
+ if (params_.max_height != 0 && height > params_.max_height) |
+ height = params_.max_height; |
+ return gfx::Size(params_.bubble_width, height); |
} |
void TrayBubbleView::OnMouseEntered(const views::MouseEvent& event) { |
@@ -309,7 +399,7 @@ void TrayBubbleView::OnMouseExited(const views::MouseEvent& event) { |
} |
void TrayBubbleView::GetAccessibleState(ui::AccessibleViewState* state) { |
- if (can_activate_) { |
+ if (params_.can_activate) { |
state->role = ui::AccessibilityTypes::ROLE_WINDOW; |
state->name = l10n_util::GetStringUTF16( |
IDS_ASH_STATUS_TRAY_ACCESSIBLE_NAME); |
@@ -340,10 +430,25 @@ TrayBubbleView::Host::~Host() { |
Shell::GetInstance()->RemoveEnvEventFilter(this); |
} |
-void TrayBubbleView::Host::InitializeHost(views::Widget* widget, |
- views::View* tray_view) { |
+void TrayBubbleView::Host::PostCreateBubble(views::Widget* widget, |
+ TrayBubbleView* bubble_view, |
+ views::View* tray_view) { |
widget_ = widget; |
tray_view_ = tray_view; |
+ |
+ // Must occur after call to BubbleDelegateView::CreateBubble(). |
+ bubble_view->SetAlignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); |
+ |
+ // Setup animation. |
+ ash::SetWindowVisibilityAnimationType( |
+ widget->GetNativeWindow(), |
+ ash::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE); |
+ ash::SetWindowVisibilityAnimationTransition( |
+ widget->GetNativeWindow(), |
+ ash::ANIMATE_BOTH); |
+ ash::SetWindowVisibilityAnimationDuration( |
+ widget->GetNativeWindow(), |
+ base::TimeDelta::FromMilliseconds(kAnimationDurationForPopupMS)); |
} |
bool TrayBubbleView::Host::PreHandleKeyEvent(aura::Window* target, |