15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/bubble/bubble_delegate.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/base/accessibility/accessible_view_state.h"
8d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/slide_animation.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/color_utils.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/rect.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/native_theme/native_theme.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/bubble/bubble_frame_view.h"
134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/views/focus/view_storage.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget_observer.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_WIN)
18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/base/win/shell.h"
19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The duration of the fade animation in milliseconds.
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kHideFadeDurationMS = 200;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The defaut margin between the content and the inside border, in pixels.
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kDefaultMargin = 6;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace views {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Create a widget to host the bubble.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Widget* CreateBubbleWidget(BubbleDelegateView* bubble) {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Widget* bubble_widget = new Widget();
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Widget::InitParams bubble_params(Widget::InitParams::TYPE_BUBBLE);
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bubble_params.delegate = bubble;
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bubble_params.opacity = Widget::InitParams::TRANSLUCENT_WINDOW;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bubble_params.accept_events = bubble->accept_events();
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bubble->parent_window())
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bubble_params.parent = bubble->parent_window();
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else if (bubble->anchor_widget())
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bubble_params.parent = bubble->anchor_widget()->GetNativeView();
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bubble_params.can_activate = bubble->CanActivate();
43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bubble->OnBeforeBubbleWidgetInit(&bubble_params, bubble_widget);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bubble_widget->Init(bubble_params);
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bubble_widget;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}  // namespace
4968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BubbleDelegateView::BubbleDelegateView()
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : close_on_esc_(true),
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      close_on_deactivate_(true),
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      anchor_view_storage_id_(ViewStorage::GetInstance()->CreateStorageID()),
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      anchor_widget_(NULL),
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      move_with_anchor_(false),
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      arrow_(BubbleBorder::TOP_LEFT),
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shadow_(BubbleBorder::SMALL_SHADOW),
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      color_explicitly_set_(false),
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      margins_(kDefaultMargin, kDefaultMargin, kDefaultMargin, kDefaultMargin),
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      original_opacity_(255),
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      use_focusless_(false),
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      accept_events_(true),
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      border_accepts_events_(true),
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      adjust_if_offscreen_(true),
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent_window_(NULL) {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdateColorsFromTheme(GetNativeTheme());
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BubbleDelegateView::BubbleDelegateView(
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    View* anchor_view,
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    BubbleBorder::Arrow arrow)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : close_on_esc_(true),
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      close_on_deactivate_(true),
754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      anchor_view_storage_id_(ViewStorage::GetInstance()->CreateStorageID()),
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      anchor_widget_(NULL),
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      move_with_anchor_(false),
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      arrow_(arrow),
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shadow_(BubbleBorder::SMALL_SHADOW),
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      color_explicitly_set_(false),
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      margins_(kDefaultMargin, kDefaultMargin, kDefaultMargin, kDefaultMargin),
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      original_opacity_(255),
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      use_focusless_(false),
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      accept_events_(true),
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      border_accepts_events_(true),
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      adjust_if_offscreen_(true),
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent_window_(NULL) {
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SetAnchorView(anchor_view);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdateColorsFromTheme(GetNativeTheme());
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BubbleDelegateView::~BubbleDelegateView() {
94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  SetLayoutManager(NULL);
954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SetAnchorView(NULL);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Widget* BubbleDelegateView::CreateBubble(BubbleDelegateView* bubble_delegate) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bubble_delegate->Init();
1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Get the latest anchor widget from the anchor view at bubble creation time.
1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  bubble_delegate->SetAnchorView(bubble_delegate->GetAnchorView());
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Widget* bubble_widget = CreateBubbleWidget(bubble_delegate);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if defined(OS_WIN) && defined(USE_AURA)
106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // If glass is enabled, the bubble is allowed to extend outside the bounds of
107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // the parent frame and let DWM handle compositing.  If not, then we don't
108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // want to allow the bubble to extend the frame because it will be clipped.
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bubble_delegate->set_adjust_if_offscreen(ui::win::IsAeroGlassEnabled());
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bubble_delegate->SizeToContents();
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bubble_widget->AddObserver(bubble_delegate);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bubble_widget;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BubbleDelegateView* BubbleDelegateView::AsBubbleDelegate() {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BubbleDelegateView::CanActivate() const {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !use_focusless();
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)bool BubbleDelegateView::ShouldShowCloseButton() const {
126a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return false;
127a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
128a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)View* BubbleDelegateView::GetContentsView() {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NonClientFrameView* BubbleDelegateView::CreateNonClientFrameView(
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Widget* widget) {
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BubbleFrameView* frame = new BubbleFrameView(margins());
1364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  BubbleBorder::Arrow adjusted_arrow = arrow();
137d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)  if (base::i18n::IsRTL())
1384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    adjusted_arrow = BubbleBorder::horizontal_mirror(adjusted_arrow);
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  frame->SetBubbleBorder(new BubbleBorder(adjusted_arrow, shadow(), color()));
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return frame;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void BubbleDelegateView::GetAccessibleState(ui::AccessibleViewState* state) {
144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  state->role = ui::AccessibilityTypes::ROLE_DIALOG;
145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BubbleDelegateView::OnWidgetDestroying(Widget* widget) {
1484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (anchor_widget() == widget)
1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    SetAnchorView(NULL);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void BubbleDelegateView::OnWidgetVisibilityChanging(Widget* widget,
1533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                                    bool visible) {
1543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#if defined(OS_WIN)
1553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // On Windows we need to handle this before the bubble is visible or hidden.
1563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Please see the comment on the OnWidgetVisibilityChanging function. On
1573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // other platforms it is fine to handle it after the bubble is shown/hidden.
1583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  HandleVisibilityChanged(widget, visible);
1593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#endif
1603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BubbleDelegateView::OnWidgetVisibilityChanged(Widget* widget,
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   bool visible) {
1643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#if !defined(OS_WIN)
1653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  HandleVisibilityChanged(widget, visible);
1663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#endif
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BubbleDelegateView::OnWidgetActivationChanged(Widget* widget,
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   bool active) {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (close_on_deactivate() && widget == GetWidget() && !active)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetWidget()->Close();
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BubbleDelegateView::OnWidgetBoundsChanged(Widget* widget,
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               const gfx::Rect& new_bounds) {
177a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (anchor_widget() == widget) {
178a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (move_with_anchor())
179a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      SizeToContents();
180a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    else
181a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      GetWidget()->Close();
182a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)View* BubbleDelegateView::GetAnchorView() const {
1864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return ViewStorage::GetInstance()->RetrieveView(anchor_view_storage_id_);
1874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Rect BubbleDelegateView::GetAnchorRect() {
1904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!GetAnchorView())
191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return anchor_rect_;
1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  anchor_rect_ = GetAnchorView()->GetBoundsInScreen();
1944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  anchor_rect_.Inset(anchor_view_insets_);
1954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return anchor_rect_;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
198f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void BubbleDelegateView::OnBeforeBubbleWidgetInit(Widget::InitParams* params,
199f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                                  Widget* widget) const {
200f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
201f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BubbleDelegateView::StartFade(bool fade_in) {
2037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#if defined(USE_AURA)
2047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Use AURA's window layer animation instead of fading. This ensures that
2057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // hosts which rely on the layer animation callbacks to close the window
2067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // work correctly.
2077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (fade_in)
2087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    GetWidget()->Show();
2097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  else
2107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    GetWidget()->Close();
2117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#else
212d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  fade_animation_.reset(new gfx::SlideAnimation(this));
2137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  fade_animation_->SetSlideDuration(GetFadeDuration());
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fade_animation_->Reset(fade_in ? 0.0 : 1.0);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (fade_in) {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    original_opacity_ = 0;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetWidget()->SetOpacity(original_opacity_);
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    GetWidget()->Show();
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fade_animation_->Show();
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    original_opacity_ = 255;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fade_animation_->Hide();
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#endif
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BubbleDelegateView::ResetFade() {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fade_animation_.reset();
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetWidget()->SetOpacity(original_opacity_);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BubbleDelegateView::SetAlignment(BubbleBorder::BubbleAlignment alignment) {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetBubbleFrameView()->bubble_border()->set_alignment(alignment);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SizeToContents();
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BubbleDelegateView::SetArrowPaintType(
2387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    BubbleBorder::ArrowPaintType paint_type) {
2397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  GetBubbleFrameView()->bubble_border()->set_paint_arrow(paint_type);
2407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  SizeToContents();
2417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
2427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
243f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void BubbleDelegateView::OnAnchorBoundsChanged() {
2447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  SizeToContents();
2457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BubbleDelegateView::AcceleratorPressed(
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::Accelerator& accelerator) {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!close_on_esc() || accelerator.key_code() != ui::VKEY_ESCAPE)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (fade_animation_.get())
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fade_animation_->Reset();
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetWidget()->Close();
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BubbleDelegateView::OnNativeThemeChanged(const ui::NativeTheme* theme) {
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdateColorsFromTheme(theme);
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
261d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void BubbleDelegateView::AnimationEnded(const gfx::Animation* animation) {
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (animation != fade_animation_.get())
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool closed = fade_animation_->GetCurrentValue() == 0;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fade_animation_->Reset();
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (closed)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetWidget()->Close();
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
270d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void BubbleDelegateView::AnimationProgressed(const gfx::Animation* animation) {
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (animation != fade_animation_.get())
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(fade_animation_->is_animating());
274f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  GetWidget()->SetOpacity(fade_animation_->GetCurrentValue() * 255);
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BubbleDelegateView::Init() {}
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void BubbleDelegateView::SetAnchorView(View* anchor_view) {
2804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // When the anchor view gets set the associated anchor widget might
2814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // change as well.
2824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!anchor_view || anchor_widget() != anchor_view->GetWidget()) {
2834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (anchor_widget()) {
2844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      anchor_widget_->RemoveObserver(this);
2854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      anchor_widget_ = NULL;
2864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
2874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (anchor_view) {
2884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      anchor_widget_ = anchor_view->GetWidget();
2894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (anchor_widget_)
2904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        anchor_widget_->AddObserver(this);
2914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
2924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
2934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Remove the old storage item and set the new (if there is one).
2954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ViewStorage* view_storage = ViewStorage::GetInstance();
2964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (view_storage->RetrieveView(anchor_view_storage_id_))
2974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    view_storage->RemoveView(anchor_view_storage_id_);
2984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (anchor_view)
2994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    view_storage->StoreView(anchor_view_storage_id_, anchor_view);
300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (GetWidget())
302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    OnAnchorBoundsChanged();
303f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
304f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
305f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void BubbleDelegateView::SetAnchorRect(const gfx::Rect& rect) {
306f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  anchor_rect_ = rect;
307f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (GetWidget())
308f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    OnAnchorBoundsChanged();
3094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BubbleDelegateView::SizeToContents() {
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetWidget()->SetBounds(GetBubbleBounds());
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BubbleFrameView* BubbleDelegateView::GetBubbleFrameView() const {
316f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const NonClientView* view =
317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      GetWidget() ? GetWidget()->non_client_view() : NULL;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return view ? static_cast<BubbleFrameView*>(view->frame_view()) : NULL;
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Rect BubbleDelegateView::GetBubbleBounds() {
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The argument rect has its origin at the bubble's arrow anchor point;
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // its size is the preferred size of the bubble's client view (this view).
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetBubbleFrameView()->GetUpdatedWindowBounds(GetAnchorRect(),
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetPreferredSize(), adjust_if_offscreen_);
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)int BubbleDelegateView::GetFadeDuration() {
3297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return kHideFadeDurationMS;
3307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
3317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BubbleDelegateView::UpdateColorsFromTheme(const ui::NativeTheme* theme) {
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!color_explicitly_set_) {
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    color_ = GetNativeTheme()->GetSystemColor(
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ui::NativeTheme::kColorId_WindowBackground);
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  set_background(Background::CreateSolidBackground(color()));
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BubbleFrameView* frame_view = GetBubbleFrameView();
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (frame_view)
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    frame_view->bubble_border()->set_background_color(color());
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
343f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void BubbleDelegateView::HandleVisibilityChanged(Widget* widget, bool visible) {
344f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (widget == GetWidget() && visible && anchor_widget() &&
345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      anchor_widget()->GetTopLevelWidget()) {
346f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    anchor_widget()->GetTopLevelWidget()->DisableInactiveRendering();
3473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
3493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace views
351