1// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/ui/views/frame/contents_container.h" 6 7#include "base/logging.h" 8#include "third_party/skia/include/core/SkColor.h" 9#include "ui/base/animation/slide_animation.h" 10#include "views/background.h" 11#include "views/widget/root_view.h" 12#include "views/widget/widget.h" 13 14// Min/max opacity of the overlay. 15static const int kMinOpacity = 0; 16static const int kMaxOpacity = 192; 17 18// View used to track when the overlay widget is destroyed. If the 19// ContentsContainer is still valid when the destructor is invoked this invokes 20// |OverlayViewDestroyed| on the ContentsContainer. 21class ContentsContainer::OverlayContentView : public views::View { 22 public: 23 explicit OverlayContentView(ContentsContainer* container) 24 : container_(container) { 25 } 26 ~OverlayContentView() { 27 if (container_) 28 container_->OverlayViewDestroyed(); 29 } 30 31 void Detach() { 32 container_ = NULL; 33 } 34 35 private: 36 ContentsContainer* container_; 37 38 DISALLOW_COPY_AND_ASSIGN(OverlayContentView); 39}; 40 41ContentsContainer::ContentsContainer(views::View* active) 42 : active_(active), 43 preview_(NULL), 44 preview_tab_contents_(NULL), 45 active_overlay_(NULL), 46 overlay_view_(NULL), 47 active_top_margin_(0) { 48 AddChildView(active_); 49} 50 51ContentsContainer::~ContentsContainer() { 52 // We don't need to explicitly delete active_overlay_ as it'll be deleted by 53 // virtue of being a child window. 54 if (overlay_view_) 55 overlay_view_->Detach(); 56} 57 58void ContentsContainer::MakePreviewContentsActiveContents() { 59 DCHECK(preview_); 60 RemoveFade(); 61 62 active_ = preview_; 63 preview_ = NULL; 64 Layout(); 65} 66 67void ContentsContainer::SetPreview(views::View* preview, 68 TabContents* preview_tab_contents) { 69 if (preview == preview_) 70 return; 71 72 if (preview_) 73 RemoveChildView(preview_); 74 preview_ = preview; 75 preview_tab_contents_ = preview_tab_contents; 76 if (preview_) 77 AddChildView(preview_); 78 79 Layout(); 80} 81 82void ContentsContainer::SetActiveTopMargin(int margin) { 83 if (active_top_margin_ == margin) 84 return; 85 86 active_top_margin_ = margin; 87 // Make sure we layout next time around. We need this in case our bounds 88 // haven't changed. 89 InvalidateLayout(); 90} 91 92gfx::Rect ContentsContainer::GetPreviewBounds() { 93 gfx::Point screen_loc; 94 ConvertPointToScreen(this, &screen_loc); 95 return gfx::Rect(screen_loc, size()); 96} 97 98void ContentsContainer::FadeActiveContents() { 99 if (active_overlay_ || !ui::Animation::ShouldRenderRichAnimation()) 100 return; 101 102#if !defined(OS_WIN) 103 // TODO: fix this. I'm disabling as z-order isn't right on linux so that 104 // overlay ends up obscuring the omnibox. 105 return; 106#endif 107 108 overlay_animation_.reset(new ui::SlideAnimation(this)); 109 overlay_animation_->SetDuration(300); 110 overlay_animation_->SetSlideDuration(300); 111 overlay_animation_->Show(); 112 113 CreateOverlay(kMinOpacity); 114} 115 116void ContentsContainer::ShowFade() { 117 if (active_overlay_ || !ui::Animation::ShouldRenderRichAnimation()) 118 return; 119 120 CreateOverlay(kMaxOpacity); 121} 122 123void ContentsContainer::RemoveFade() { 124 overlay_animation_.reset(); 125 if (active_overlay_) { 126 overlay_view_->Detach(); 127 overlay_view_ = NULL; 128 active_overlay_->Close(); 129 active_overlay_ = NULL; 130 } 131} 132 133void ContentsContainer::AnimationProgressed(const ui::Animation* animation) { 134 active_overlay_->SetOpacity( 135 ui::Tween::ValueBetween(animation->GetCurrentValue(), kMinOpacity, 136 kMaxOpacity)); 137 active_overlay_->GetRootView()->SchedulePaint(); 138} 139 140void ContentsContainer::Layout() { 141 // The active view always gets the full bounds. 142 active_->SetBounds(0, active_top_margin_, width(), 143 std::max(0, height() - active_top_margin_)); 144 145 if (preview_) 146 preview_->SetBounds(0, 0, width(), height()); 147 148 // Need to invoke views::View in case any views whose bounds didn't change 149 // still need a layout. 150 views::View::Layout(); 151} 152 153void ContentsContainer::CreateOverlay(int initial_opacity) { 154 DCHECK(!active_overlay_); 155 views::Widget::CreateParams params(views::Widget::CreateParams::TYPE_POPUP); 156 params.transparent = true; 157 params.accept_events = false; 158 active_overlay_ = views::Widget::CreateWidget(params); 159 active_overlay_->SetOpacity(initial_opacity); 160 gfx::Point screen_origin; 161 views::View::ConvertPointToScreen(active_, &screen_origin); 162 gfx::Rect overlay_bounds(screen_origin, active_->size()); 163 active_overlay_->Init(active_->GetWidget()->GetNativeView(), overlay_bounds); 164 overlay_view_ = new OverlayContentView(this); 165 overlay_view_->set_background( 166 views::Background::CreateSolidBackground(SK_ColorWHITE)); 167 active_overlay_->SetContentsView(overlay_view_); 168 active_overlay_->Show(); 169 active_overlay_->MoveAboveWidget(active_->GetWidget()); 170} 171 172void ContentsContainer::OverlayViewDestroyed() { 173 active_overlay_ = NULL; 174 overlay_view_ = NULL; 175} 176