// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/ui/views/frame/contents_container.h" #include "base/logging.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/base/animation/slide_animation.h" #include "views/background.h" #include "views/widget/root_view.h" #include "views/widget/widget.h" // Min/max opacity of the overlay. static const int kMinOpacity = 0; static const int kMaxOpacity = 192; // View used to track when the overlay widget is destroyed. If the // ContentsContainer is still valid when the destructor is invoked this invokes // |OverlayViewDestroyed| on the ContentsContainer. class ContentsContainer::OverlayContentView : public views::View { public: explicit OverlayContentView(ContentsContainer* container) : container_(container) { } ~OverlayContentView() { if (container_) container_->OverlayViewDestroyed(); } void Detach() { container_ = NULL; } private: ContentsContainer* container_; DISALLOW_COPY_AND_ASSIGN(OverlayContentView); }; ContentsContainer::ContentsContainer(views::View* active) : active_(active), preview_(NULL), preview_tab_contents_(NULL), active_overlay_(NULL), overlay_view_(NULL), active_top_margin_(0) { AddChildView(active_); } ContentsContainer::~ContentsContainer() { // We don't need to explicitly delete active_overlay_ as it'll be deleted by // virtue of being a child window. if (overlay_view_) overlay_view_->Detach(); } void ContentsContainer::MakePreviewContentsActiveContents() { DCHECK(preview_); RemoveFade(); active_ = preview_; preview_ = NULL; Layout(); } void ContentsContainer::SetPreview(views::View* preview, TabContents* preview_tab_contents) { if (preview == preview_) return; if (preview_) RemoveChildView(preview_); preview_ = preview; preview_tab_contents_ = preview_tab_contents; if (preview_) AddChildView(preview_); Layout(); } void ContentsContainer::SetActiveTopMargin(int margin) { if (active_top_margin_ == margin) return; active_top_margin_ = margin; // Make sure we layout next time around. We need this in case our bounds // haven't changed. InvalidateLayout(); } gfx::Rect ContentsContainer::GetPreviewBounds() { gfx::Point screen_loc; ConvertPointToScreen(this, &screen_loc); return gfx::Rect(screen_loc, size()); } void ContentsContainer::FadeActiveContents() { if (active_overlay_ || !ui::Animation::ShouldRenderRichAnimation()) return; #if !defined(OS_WIN) // TODO: fix this. I'm disabling as z-order isn't right on linux so that // overlay ends up obscuring the omnibox. return; #endif overlay_animation_.reset(new ui::SlideAnimation(this)); overlay_animation_->SetDuration(300); overlay_animation_->SetSlideDuration(300); overlay_animation_->Show(); CreateOverlay(kMinOpacity); } void ContentsContainer::ShowFade() { if (active_overlay_ || !ui::Animation::ShouldRenderRichAnimation()) return; CreateOverlay(kMaxOpacity); } void ContentsContainer::RemoveFade() { overlay_animation_.reset(); if (active_overlay_) { overlay_view_->Detach(); overlay_view_ = NULL; active_overlay_->Close(); active_overlay_ = NULL; } } void ContentsContainer::AnimationProgressed(const ui::Animation* animation) { active_overlay_->SetOpacity( ui::Tween::ValueBetween(animation->GetCurrentValue(), kMinOpacity, kMaxOpacity)); active_overlay_->GetRootView()->SchedulePaint(); } void ContentsContainer::Layout() { // The active view always gets the full bounds. active_->SetBounds(0, active_top_margin_, width(), std::max(0, height() - active_top_margin_)); if (preview_) preview_->SetBounds(0, 0, width(), height()); // Need to invoke views::View in case any views whose bounds didn't change // still need a layout. views::View::Layout(); } void ContentsContainer::CreateOverlay(int initial_opacity) { DCHECK(!active_overlay_); views::Widget::CreateParams params(views::Widget::CreateParams::TYPE_POPUP); params.transparent = true; params.accept_events = false; active_overlay_ = views::Widget::CreateWidget(params); active_overlay_->SetOpacity(initial_opacity); gfx::Point screen_origin; views::View::ConvertPointToScreen(active_, &screen_origin); gfx::Rect overlay_bounds(screen_origin, active_->size()); active_overlay_->Init(active_->GetWidget()->GetNativeView(), overlay_bounds); overlay_view_ = new OverlayContentView(this); overlay_view_->set_background( views::Background::CreateSolidBackground(SK_ColorWHITE)); active_overlay_->SetContentsView(overlay_view_); active_overlay_->Show(); active_overlay_->MoveAboveWidget(active_->GetWidget()); } void ContentsContainer::OverlayViewDestroyed() { active_overlay_ = NULL; overlay_view_ = NULL; }