bubble_delegate.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// Use of this source code is governed by a BSD-style license that can be
3bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// found in the LICENSE file.
4bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "ui/views/bubble/bubble_delegate.h"
6ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
7bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "ui/gfx/animation/slide_animation.h"
8bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "ui/gfx/color_utils.h"
9bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "ui/gfx/rect.h"
10bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "ui/native_theme/native_theme.h"
11bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "ui/views/bubble/bubble_frame_view.h"
12bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "ui/views/focus/view_storage.h"
13bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "ui/views/widget/widget.h"
14bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "ui/views/widget/widget_observer.h"
15bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
16731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#if defined(OS_WIN)
17bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "ui/base/win/shell.h"
18bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#endif
19bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
20bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// The duration of the fade animation in milliseconds.
21731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickstatic const int kHideFadeDurationMS = 200;
22731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
23731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// The defaut margin between the content and the inside border, in pixels.
24bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenstatic const int kDefaultMargin = 6;
25bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
26bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsennamespace views {
27731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
28731df977c0511bca2206b5f333555b1205ff1f43Iain Merricknamespace {
29731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
30bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// Create a widget to host the bubble.
31bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian MonsenWidget* CreateBubbleWidget(BubbleDelegateView* bubble) {
32bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  Widget* bubble_widget = new Widget();
33bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  Widget::InitParams bubble_params(Widget::InitParams::TYPE_BUBBLE);
34bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  bubble_params.delegate = bubble;
35bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  bubble_params.opacity = Widget::InitParams::TRANSLUCENT_WINDOW;
36bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  bubble_params.accept_events = bubble->accept_events();
37bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  if (bubble->parent_window())
38bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    bubble_params.parent = bubble->parent_window();
39bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  else if (bubble->anchor_widget())
40bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    bubble_params.parent = bubble->anchor_widget()->GetNativeView();
41bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  bubble_params.can_activate = bubble->CanActivate();
42bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#if defined(OS_WIN) && !defined(USE_AURA)
43bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  bubble_params.type = Widget::InitParams::TYPE_WINDOW_FRAMELESS;
44bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  bubble_params.opacity = Widget::InitParams::OPAQUE_WINDOW;
45bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#endif
46bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  bubble_widget->Init(bubble_params);
47bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  return bubble_widget;
48bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
49bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
50bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}  // namespace
51bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
52bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#if defined(OS_WIN) && !defined(USE_AURA)
53bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// Windows uses two widgets and some extra complexity to host partially
54bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// transparent native controls and use per-pixel HWND alpha on the border.
55bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// TODO(msw): Clean these up when Windows native controls are no longer needed.
56bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenclass BubbleBorderDelegate : public WidgetDelegate,
57bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                             public WidgetObserver {
58bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen public:
59bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  BubbleBorderDelegate(BubbleDelegateView* bubble, Widget* widget)
60bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      : bubble_(bubble),
61bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen        widget_(widget) {
62bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    bubble_->GetWidget()->AddObserver(this);
63bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  }
64bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
65bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual ~BubbleBorderDelegate() {
66731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    DetachFromBubble();
67bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  }
68bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
69bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // WidgetDelegate overrides:
70bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual bool CanActivate() const OVERRIDE { return false; }
71bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual string16 GetWindowTitle() const OVERRIDE {
72bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    return bubble_->GetWindowTitle();
73bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  }
74bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual bool ShouldShowCloseButton() const OVERRIDE {
75bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    return bubble_->ShouldShowCloseButton();
76bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  }
77bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual void DeleteDelegate() OVERRIDE { delete this; }
78bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual Widget* GetWidget() OVERRIDE { return widget_; }
79bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual const Widget* GetWidget() const OVERRIDE { return widget_; }
80bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual NonClientFrameView* CreateNonClientFrameView(
81bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      Widget* widget) OVERRIDE {
82bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    return bubble_->CreateNonClientFrameView(widget);
83bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  }
84bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
85bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // WidgetObserver overrides:
86bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual void OnWidgetDestroying(Widget* widget) OVERRIDE {
87bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    DetachFromBubble();
88bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    widget_->Close();
89bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  }
90bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
91bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen private:
92bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // Removes state installed on |bubble_|, including references |bubble_| has to
93bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // us.
94bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  void DetachFromBubble() {
95bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    if (!bubble_)
96bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      return;
97bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    if (bubble_->GetWidget())
98bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      bubble_->GetWidget()->RemoveObserver(this);
99bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    bubble_->border_widget_ = NULL;
100bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    bubble_ = NULL;
101bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  }
102bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
103bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  BubbleDelegateView* bubble_;
104bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  Widget* widget_;
105bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
106bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  DISALLOW_COPY_AND_ASSIGN(BubbleBorderDelegate);
107bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen};
108bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
109bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsennamespace {
110bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
111bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// Create a widget to host the bubble's border.
112bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian MonsenWidget* CreateBorderWidget(BubbleDelegateView* bubble) {
113bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  Widget* border_widget = new Widget();
114bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  Widget::InitParams border_params(Widget::InitParams::TYPE_BUBBLE);
115bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  border_params.delegate = new BubbleBorderDelegate(bubble, border_widget);
116bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  border_params.opacity = Widget::InitParams::TRANSLUCENT_WINDOW;
117bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  border_params.parent = bubble->GetWidget()->GetNativeView();
118bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  border_params.can_activate = false;
119bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  border_params.accept_events = bubble->border_accepts_events();
120bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  border_widget->Init(border_params);
121bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  border_widget->set_focus_on_creation(false);
122bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  return border_widget;
123bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
124bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
125bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}  // namespace
126bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
127bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#endif
128bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
129bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian MonsenBubbleDelegateView::BubbleDelegateView()
130bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    : close_on_esc_(true),
131bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      close_on_deactivate_(true),
132bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      anchor_view_storage_id_(ViewStorage::GetInstance()->CreateStorageID()),
133bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      anchor_widget_(NULL),
134bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      move_with_anchor_(false),
135bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      arrow_(BubbleBorder::TOP_LEFT),
136bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      shadow_(BubbleBorder::SMALL_SHADOW),
137bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      color_explicitly_set_(false),
138bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      margins_(kDefaultMargin, kDefaultMargin, kDefaultMargin, kDefaultMargin),
139bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      original_opacity_(255),
140bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      border_widget_(NULL),
141bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      use_focusless_(false),
142bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      accept_events_(true),
143bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      border_accepts_events_(true),
144bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      adjust_if_offscreen_(true),
145bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      parent_window_(NULL) {
146bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
147bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  UpdateColorsFromTheme(GetNativeTheme());
148bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
149bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
150bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian MonsenBubbleDelegateView::BubbleDelegateView(
151bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    View* anchor_view,
152bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    BubbleBorder::Arrow arrow)
153bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    : close_on_esc_(true),
154bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      close_on_deactivate_(true),
155bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      anchor_view_storage_id_(ViewStorage::GetInstance()->CreateStorageID()),
156bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      anchor_widget_(NULL),
157bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      move_with_anchor_(false),
158bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      arrow_(arrow),
159bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      shadow_(BubbleBorder::SMALL_SHADOW),
160bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      color_explicitly_set_(false),
161bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      margins_(kDefaultMargin, kDefaultMargin, kDefaultMargin, kDefaultMargin),
162bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      original_opacity_(255),
163bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      border_widget_(NULL),
164bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      use_focusless_(false),
165      accept_events_(true),
166      border_accepts_events_(true),
167      adjust_if_offscreen_(true),
168      parent_window_(NULL) {
169  SetAnchorView(anchor_view);
170  AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
171  UpdateColorsFromTheme(GetNativeTheme());
172}
173
174BubbleDelegateView::~BubbleDelegateView() {
175  SetAnchorView(NULL);
176}
177
178// static
179Widget* BubbleDelegateView::CreateBubble(BubbleDelegateView* bubble_delegate) {
180  bubble_delegate->Init();
181  // Get the latest anchor widget from the anchor view at bubble creation time.
182  bubble_delegate->SetAnchorView(bubble_delegate->GetAnchorView());
183  Widget* bubble_widget = CreateBubbleWidget(bubble_delegate);
184
185#if defined(OS_WIN)
186#if defined(USE_AURA)
187  // If glass is enabled, the bubble is allowed to extend outside the bounds of
188  // the parent frame and let DWM handle compositing.  If not, then we don't
189  // want to allow the bubble to extend the frame because it will be clipped.
190  bubble_delegate->set_adjust_if_offscreen(ui::win::IsAeroGlassEnabled());
191#else
192  // First set the contents view to initialize view bounds for widget sizing.
193  bubble_widget->SetContentsView(bubble_delegate->GetContentsView());
194  bubble_delegate->border_widget_ = CreateBorderWidget(bubble_delegate);
195#endif
196#endif
197
198  bubble_delegate->SizeToContents();
199  bubble_widget->AddObserver(bubble_delegate);
200  return bubble_widget;
201}
202
203BubbleDelegateView* BubbleDelegateView::AsBubbleDelegate() {
204  return this;
205}
206
207bool BubbleDelegateView::CanActivate() const {
208  return !use_focusless();
209}
210
211bool BubbleDelegateView::ShouldShowCloseButton() const {
212  return false;
213}
214
215View* BubbleDelegateView::GetContentsView() {
216  return this;
217}
218
219NonClientFrameView* BubbleDelegateView::CreateNonClientFrameView(
220    Widget* widget) {
221  BubbleFrameView* frame = new BubbleFrameView(margins());
222  BubbleBorder::Arrow adjusted_arrow = arrow();
223  if (ShouldFlipArrowForRtl() && base::i18n::IsRTL())
224    adjusted_arrow = BubbleBorder::horizontal_mirror(adjusted_arrow);
225  frame->SetBubbleBorder(new BubbleBorder(adjusted_arrow, shadow(), color()));
226  return frame;
227}
228
229void BubbleDelegateView::OnWidgetDestroying(Widget* widget) {
230  if (anchor_widget() == widget)
231    SetAnchorView(NULL);
232}
233
234void BubbleDelegateView::OnWidgetVisibilityChanging(Widget* widget,
235                                                    bool visible) {
236#if defined(OS_WIN)
237  // On Windows we need to handle this before the bubble is visible or hidden.
238  // Please see the comment on the OnWidgetVisibilityChanging function. On
239  // other platforms it is fine to handle it after the bubble is shown/hidden.
240  HandleVisibilityChanged(widget, visible);
241#endif
242}
243
244void BubbleDelegateView::OnWidgetVisibilityChanged(Widget* widget,
245                                                   bool visible) {
246#if !defined(OS_WIN)
247  HandleVisibilityChanged(widget, visible);
248#endif
249}
250
251void BubbleDelegateView::OnWidgetActivationChanged(Widget* widget,
252                                                   bool active) {
253  if (close_on_deactivate() && widget == GetWidget() && !active)
254    GetWidget()->Close();
255}
256
257void BubbleDelegateView::OnWidgetBoundsChanged(Widget* widget,
258                                               const gfx::Rect& new_bounds) {
259  if (move_with_anchor() && anchor_widget() == widget)
260    SizeToContents();
261}
262
263View* BubbleDelegateView::GetAnchorView() const {
264  return ViewStorage::GetInstance()->RetrieveView(anchor_view_storage_id_);
265}
266
267gfx::Rect BubbleDelegateView::GetAnchorRect() {
268  if (!GetAnchorView())
269    return anchor_rect_;
270
271  anchor_rect_ = GetAnchorView()->GetBoundsInScreen();
272  anchor_rect_.Inset(anchor_view_insets_);
273  return anchor_rect_;
274}
275
276void BubbleDelegateView::StartFade(bool fade_in) {
277#if defined(USE_AURA)
278  // Use AURA's window layer animation instead of fading. This ensures that
279  // hosts which rely on the layer animation callbacks to close the window
280  // work correctly.
281  if (fade_in)
282    GetWidget()->Show();
283  else
284    GetWidget()->Close();
285#else
286  fade_animation_.reset(new gfx::SlideAnimation(this));
287  fade_animation_->SetSlideDuration(GetFadeDuration());
288  fade_animation_->Reset(fade_in ? 0.0 : 1.0);
289  if (fade_in) {
290    original_opacity_ = 0;
291    if (border_widget_)
292      border_widget_->SetOpacity(original_opacity_);
293    GetWidget()->SetOpacity(original_opacity_);
294    GetWidget()->Show();
295    fade_animation_->Show();
296  } else {
297    original_opacity_ = 255;
298    fade_animation_->Hide();
299  }
300#endif
301}
302
303void BubbleDelegateView::ResetFade() {
304  fade_animation_.reset();
305  if (border_widget_)
306    border_widget_->SetOpacity(original_opacity_);
307  GetWidget()->SetOpacity(original_opacity_);
308}
309
310void BubbleDelegateView::SetAlignment(BubbleBorder::BubbleAlignment alignment) {
311  GetBubbleFrameView()->bubble_border()->set_alignment(alignment);
312  SizeToContents();
313}
314
315void BubbleDelegateView::SetArrowPaintType(
316    BubbleBorder::ArrowPaintType paint_type) {
317  GetBubbleFrameView()->bubble_border()->set_paint_arrow(paint_type);
318  SizeToContents();
319}
320
321void BubbleDelegateView::OnAnchorViewBoundsChanged() {
322  SizeToContents();
323}
324
325bool BubbleDelegateView::AcceleratorPressed(
326    const ui::Accelerator& accelerator) {
327  if (!close_on_esc() || accelerator.key_code() != ui::VKEY_ESCAPE)
328    return false;
329  if (fade_animation_.get())
330    fade_animation_->Reset();
331  GetWidget()->Close();
332  return true;
333}
334
335void BubbleDelegateView::OnNativeThemeChanged(const ui::NativeTheme* theme) {
336  UpdateColorsFromTheme(theme);
337}
338
339void BubbleDelegateView::AnimationEnded(const gfx::Animation* animation) {
340  if (animation != fade_animation_.get())
341    return;
342  bool closed = fade_animation_->GetCurrentValue() == 0;
343  fade_animation_->Reset();
344  if (closed)
345    GetWidget()->Close();
346}
347
348void BubbleDelegateView::AnimationProgressed(const gfx::Animation* animation) {
349  if (animation != fade_animation_.get())
350    return;
351  DCHECK(fade_animation_->is_animating());
352  unsigned char opacity = fade_animation_->GetCurrentValue() * 255;
353#if defined(OS_WIN) && !defined(USE_AURA)
354  // Explicitly set the content Widget's layered style and set transparency via
355  // SetLayeredWindowAttributes. This is done because initializing the Widget as
356  // transparent and setting opacity via UpdateLayeredWindow doesn't support
357  // hosting child native Windows controls.
358  const HWND hwnd = GetWidget()->GetNativeView();
359  const DWORD style = GetWindowLong(hwnd, GWL_EXSTYLE);
360  if ((opacity == 255) == !!(style & WS_EX_LAYERED))
361    SetWindowLong(hwnd, GWL_EXSTYLE, style ^ WS_EX_LAYERED);
362  SetLayeredWindowAttributes(hwnd, 0, opacity, LWA_ALPHA);
363  // Update the border widget's opacity.
364  border_widget_->SetOpacity(opacity);
365#endif
366  GetWidget()->SetOpacity(opacity);
367}
368
369void BubbleDelegateView::Init() {}
370
371bool BubbleDelegateView::ShouldFlipArrowForRtl() const {
372  return true;
373}
374
375void BubbleDelegateView::SetAnchorView(View* anchor_view) {
376  // When the anchor view gets set the associated anchor widget might
377  // change as well.
378  if (!anchor_view || anchor_widget() != anchor_view->GetWidget()) {
379    if (anchor_widget()) {
380      anchor_widget_->RemoveObserver(this);
381      anchor_widget_ = NULL;
382    }
383    if (anchor_view) {
384      anchor_widget_ = anchor_view->GetWidget();
385      if (anchor_widget_)
386        anchor_widget_->AddObserver(this);
387    }
388  }
389
390  // Remove the old storage item and set the new (if there is one).
391  ViewStorage* view_storage = ViewStorage::GetInstance();
392  if (view_storage->RetrieveView(anchor_view_storage_id_))
393    view_storage->RemoveView(anchor_view_storage_id_);
394
395  if (anchor_view)
396    view_storage->StoreView(anchor_view_storage_id_, anchor_view);
397}
398
399void BubbleDelegateView::SizeToContents() {
400#if defined(OS_WIN) && !defined(USE_AURA)
401  border_widget_->SetBounds(GetBubbleBounds());
402  GetWidget()->SetBounds(GetBubbleClientBounds());
403
404  // Update the local client bounds clipped out by the border widget background.
405  // Used to correctly display overlapping semi-transparent widgets on Windows.
406  GetBubbleFrameView()->bubble_border()->set_client_bounds(
407      GetBubbleFrameView()->GetBoundsForClientView());
408#else
409  GetWidget()->SetBounds(GetBubbleBounds());
410#endif
411}
412
413BubbleFrameView* BubbleDelegateView::GetBubbleFrameView() const {
414  const Widget* widget = border_widget_ ? border_widget_ : GetWidget();
415  const NonClientView* view = widget ? widget->non_client_view() : NULL;
416  return view ? static_cast<BubbleFrameView*>(view->frame_view()) : NULL;
417}
418
419gfx::Rect BubbleDelegateView::GetBubbleBounds() {
420  // The argument rect has its origin at the bubble's arrow anchor point;
421  // its size is the preferred size of the bubble's client view (this view).
422  return GetBubbleFrameView()->GetUpdatedWindowBounds(GetAnchorRect(),
423      GetPreferredSize(), adjust_if_offscreen_);
424}
425
426int BubbleDelegateView::GetFadeDuration() {
427  return kHideFadeDurationMS;
428}
429
430void BubbleDelegateView::UpdateColorsFromTheme(const ui::NativeTheme* theme) {
431  if (!color_explicitly_set_) {
432    color_ = GetNativeTheme()->GetSystemColor(
433        ui::NativeTheme::kColorId_WindowBackground);
434  }
435  set_background(Background::CreateSolidBackground(color()));
436  BubbleFrameView* frame_view = GetBubbleFrameView();
437  if (frame_view)
438    frame_view->bubble_border()->set_background_color(color());
439}
440
441#if defined(OS_WIN) && !defined(USE_AURA)
442gfx::Rect BubbleDelegateView::GetBubbleClientBounds() const {
443  gfx::Rect client_bounds(GetBubbleFrameView()->GetBoundsForClientView());
444  client_bounds.Offset(
445      border_widget_->GetWindowBoundsInScreen().OffsetFromOrigin());
446  return client_bounds;
447}
448#endif
449
450void BubbleDelegateView::HandleVisibilityChanged(Widget* widget,
451                                                 bool visible) {
452  if (widget != GetWidget())
453    return;
454
455  if (visible) {
456    if (border_widget_)
457      border_widget_->ShowInactive();
458    if (anchor_widget() && anchor_widget()->GetTopLevelWidget())
459      anchor_widget()->GetTopLevelWidget()->DisableInactiveRendering();
460  } else {
461    if (border_widget_)
462      border_widget_->Hide();
463  }
464}
465
466}  // namespace views
467