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