contents_container.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
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  RemoveFade();
60
61  active_ = preview_;
62  preview_ = NULL;
63  Layout();
64}
65
66void ContentsContainer::SetPreview(views::View* preview,
67                                   TabContents* preview_tab_contents) {
68  if (preview == preview_)
69    return;
70
71  if (preview_)
72    RemoveChildView(preview_);
73  preview_ = preview;
74  preview_tab_contents_ = preview_tab_contents;
75  if (preview_)
76    AddChildView(preview_);
77
78  Layout();
79}
80
81void ContentsContainer::SetActiveTopMargin(int margin) {
82  if (active_top_margin_ == margin)
83    return;
84
85  active_top_margin_ = margin;
86  // Make sure we layout next time around. We need this in case our bounds
87  // haven't changed.
88  InvalidateLayout();
89}
90
91gfx::Rect ContentsContainer::GetPreviewBounds() {
92  gfx::Point screen_loc;
93  ConvertPointToScreen(this, &screen_loc);
94  return gfx::Rect(screen_loc, size());
95}
96
97void ContentsContainer::FadeActiveContents() {
98  if (active_overlay_ || !ui::Animation::ShouldRenderRichAnimation())
99    return;
100
101#if !defined(OS_WIN)
102  // TODO: fix this. I'm disabling as z-order isn't right on linux so that
103  // overlay ends up obscuring the omnibox.
104  return;
105#endif
106
107  overlay_animation_.reset(new ui::SlideAnimation(this));
108  overlay_animation_->SetDuration(300);
109  overlay_animation_->SetSlideDuration(300);
110  overlay_animation_->Show();
111
112  CreateOverlay(kMinOpacity);
113}
114
115void ContentsContainer::ShowFade() {
116  if (active_overlay_ || !ui::Animation::ShouldRenderRichAnimation())
117    return;
118
119  CreateOverlay(kMaxOpacity);
120}
121
122void ContentsContainer::RemoveFade() {
123  overlay_animation_.reset();
124  if (active_overlay_) {
125    overlay_view_->Detach();
126    overlay_view_ = NULL;
127    active_overlay_->Close();
128    active_overlay_ = NULL;
129  }
130}
131
132void ContentsContainer::AnimationProgressed(const ui::Animation* animation) {
133  active_overlay_->SetOpacity(
134      ui::Tween::ValueBetween(animation->GetCurrentValue(), kMinOpacity,
135                              kMaxOpacity));
136  active_overlay_->GetRootView()->SchedulePaint();
137}
138
139void ContentsContainer::Layout() {
140  // The active view always gets the full bounds.
141  active_->SetBounds(0, active_top_margin_, width(),
142                     std::max(0, height() - active_top_margin_));
143
144  if (preview_)
145    preview_->SetBounds(0, 0, width(), height());
146
147  // Need to invoke views::View in case any views whose bounds didn't change
148  // still need a layout.
149  views::View::Layout();
150}
151
152void ContentsContainer::CreateOverlay(int initial_opacity) {
153  DCHECK(!active_overlay_);
154  active_overlay_ = views::Widget::CreatePopupWidget(views::Widget::Transparent,
155                                              views::Widget::NotAcceptEvents,
156                                              views::Widget::DeleteOnDestroy,
157                                              views::Widget::MirrorOriginInRTL);
158  active_overlay_->SetOpacity(initial_opacity);
159  gfx::Point screen_origin;
160  views::View::ConvertPointToScreen(active_, &screen_origin);
161  gfx::Rect overlay_bounds(screen_origin, active_->size());
162  active_overlay_->Init(active_->GetWidget()->GetNativeView(), overlay_bounds);
163  overlay_view_ = new OverlayContentView(this);
164  overlay_view_->set_background(
165      views::Background::CreateSolidBackground(SK_ColorWHITE));
166  active_overlay_->SetContentsView(overlay_view_);
167  active_overlay_->Show();
168  active_overlay_->MoveAbove(active_->GetWidget());
169}
170
171void ContentsContainer::OverlayViewDestroyed() {
172  active_overlay_ = NULL;
173  overlay_view_ = NULL;
174}
175