| Index: chrome/browser/ui/views/immersive_mode_controller.cc
|
| diff --git a/chrome/browser/ui/views/immersive_mode_controller.cc b/chrome/browser/ui/views/immersive_mode_controller.cc
|
| index 09773626db42533d3cf563fbb1cb4dbd04994f26..c92e9a654180882e05c10c430bf845dc836429d6 100644
|
| --- a/chrome/browser/ui/views/immersive_mode_controller.cc
|
| +++ b/chrome/browser/ui/views/immersive_mode_controller.cc
|
| @@ -4,10 +4,16 @@
|
|
|
| #include "chrome/browser/ui/views/immersive_mode_controller.h"
|
|
|
| +#include "chrome/browser/ui/views/frame/browser_frame.h"
|
| #include "chrome/browser/ui/views/frame/browser_view.h"
|
| #include "chrome/browser/ui/views/frame/contents_container.h"
|
| #include "chrome/browser/ui/views/tabs/tab_strip.h"
|
| +#include "chrome/browser/ui/views/toolbar_view.h"
|
| +#include "ui/compositor/scoped_layer_animation_settings.h"
|
| +#include "ui/gfx/transform.h"
|
| #include "ui/views/mouse_watcher_view_host.h"
|
| +#include "ui/views/view.h"
|
| +#include "ui/views/window/non_client_view.h"
|
|
|
| #if defined(USE_AURA)
|
| #include "ui/aura/window.h"
|
| @@ -24,21 +30,125 @@ const int kHideDelayMs = 200;
|
|
|
| } // namespace
|
|
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +// View to hold the tab strip, toolbar, and sometimes the bookmark bar during
|
| +// an immersive mode reveal. Paints on top of other layers in order to appear
|
| +// over the web contents. Immersive mode uses this view to avoid changing the
|
| +// BrowserView's view structure in the steady state.
|
| +// TODO(jamescook): If immersive mode becomes non-experimental, use a permanent
|
| +// top-of-window container view in BrowserView instead of RevealView to avoid
|
| +// reparenting.
|
| +// TODO(jamescook): Bookmark bar does not yet work.
|
| +class RevealView : public views::View {
|
| + public:
|
| + explicit RevealView(BrowserView* browser_view);
|
| + virtual ~RevealView();
|
| +
|
| + // Reparents the |browser_view_| tab strip, toolbar, and bookmark bar to
|
| + // this view.
|
| + void AcquireTopViews();
|
| +
|
| + // Reparents tab strip, toolbar, and bookmark bar back to |browser_view_|.
|
| + void ReleaseTopViews();
|
| +
|
| + // views::View overrides:
|
| + virtual void PaintChildren(gfx::Canvas* canvas) OVERRIDE;
|
| +
|
| + private:
|
| + // None of these views are owned.
|
| + BrowserView* browser_view_;
|
| + TabStrip* tabstrip_;
|
| + ToolbarView* toolbar_view_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(RevealView);
|
| +};
|
| +
|
| +RevealView::RevealView(BrowserView* browser_view)
|
| + : browser_view_(browser_view),
|
| + tabstrip_(NULL),
|
| + toolbar_view_(NULL) {
|
| + SetPaintToLayer(true);
|
| + SetFillsBoundsOpaquely(true);
|
| +}
|
| +
|
| +RevealView::~RevealView() {}
|
| +
|
| +void RevealView::AcquireTopViews() {
|
| + // Reparenting causes hit tests that require a parent for |this|.
|
| + DCHECK(parent());
|
| +
|
| + tabstrip_ = browser_view_->tabstrip();
|
| + toolbar_view_ = browser_view_->GetToolbarView();
|
| +
|
| + // Ensure the indices are what we expect before we start moving the views.
|
| + DCHECK_EQ(browser_view_->GetIndexOf(tabstrip_), BrowserView::kTabstripIndex);
|
| + DCHECK_EQ(browser_view_->GetIndexOf(toolbar_view_),
|
| + BrowserView::kToolbarIndex);
|
| +
|
| + AddChildView(tabstrip_);
|
| + AddChildView(toolbar_view_);
|
| +
|
| + // Set our initial bounds, which triggers a Layout().
|
| + int width = parent()->width();
|
| + int height = toolbar_view_->bounds().bottom();
|
| + SetBounds(0, 0, width, height);
|
| +}
|
| +
|
| +void RevealView::ReleaseTopViews() {
|
| + // Reparenting causes hit tests that require a parent for |this|.
|
| + DCHECK(parent());
|
| +
|
| + browser_view_->AddChildViewAt(tabstrip_, BrowserView::kTabstripIndex);
|
| + browser_view_->AddChildViewAt(toolbar_view_, BrowserView::kToolbarIndex);
|
| +
|
| + // Ensure the newly restored views get painted.
|
| + tabstrip_->SchedulePaint();
|
| + toolbar_view_->SchedulePaint();
|
| +
|
| + tabstrip_ = NULL;
|
| + toolbar_view_ = NULL;
|
| +}
|
| +
|
| +void RevealView::PaintChildren(gfx::Canvas* canvas) {
|
| + // Top-views depend on parts of the frame (themes, window buttons) being
|
| + // painted underneath them. Clip rect has already been set to the bounds
|
| + // of this view, so just paint the frame.
|
| + views::View* frame = browser_view_->frame()->GetFrameView();
|
| + frame->Paint(canvas);
|
| +
|
| + views::View::PaintChildren(canvas);
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +
|
| ImmersiveModeController::ImmersiveModeController(BrowserView* browser_view)
|
| : browser_view_(browser_view),
|
| enabled_(false),
|
| - hide_top_views_(false) {
|
| + revealed_(false) {
|
| }
|
|
|
| -ImmersiveModeController::~ImmersiveModeController() {}
|
| +ImmersiveModeController::~ImmersiveModeController() {
|
| + // Ensure views are reparented if we are deleted mid-reveal.
|
| + if (reveal_view_.get()) {
|
| + reveal_view_->ReleaseTopViews();
|
| + ResetRevealView();
|
| + }
|
| +}
|
|
|
| void ImmersiveModeController::SetEnabled(bool enabled) {
|
| if (enabled_ == enabled)
|
| return;
|
| enabled_ = enabled;
|
| - hide_top_views_ = enabled;
|
| - browser_view_->tabstrip()->SetImmersiveStyle(enabled_);
|
| - browser_view_->Layout();
|
| +
|
| + if (enabled_) {
|
| + browser_view_->tabstrip()->SetImmersiveStyle(true);
|
| + browser_view_->Layout();
|
| + } else {
|
| + // Don't Layout() browser_view_ because EndReveal() does so.
|
| + EndReveal(false);
|
| + top_timer_.Stop();
|
| + }
|
|
|
| #if defined(USE_AURA)
|
| // TODO(jamescook): If we want to port this feature to non-Aura views we'll
|
| @@ -51,38 +161,6 @@ void ImmersiveModeController::SetEnabled(bool enabled) {
|
| else
|
| browser_view_->GetNativeWindow()->RemovePreTargetHandler(this);
|
| #endif // defined(USE_AURA)
|
| -
|
| - if (!enabled_) {
|
| - // Stop watching the mouse on disable.
|
| - mouse_watcher_.reset();
|
| - top_timer_.Stop();
|
| - }
|
| -}
|
| -
|
| -void ImmersiveModeController::RevealTopViews() {
|
| - if (!hide_top_views_)
|
| - return;
|
| - hide_top_views_ = false;
|
| -
|
| - // Recompute the bounds of the views when painted normally.
|
| - browser_view_->tabstrip()->SetImmersiveStyle(false);
|
| - browser_view_->Layout();
|
| -
|
| - // Compute the top of the content area in order to find the bottom of all
|
| - // the top-of-window views like toolbar, bookmarks, etc.
|
| - gfx::Point content_origin(0, 0);
|
| - views::View::ConvertPointToTarget(
|
| - browser_view_->contents(), browser_view_, &content_origin);
|
| -
|
| - // Stop the immersive reveal when the mouse leaves the top-of-window area.
|
| - gfx::Insets insets(0, 0, content_origin.y() - browser_view_->height(), 0);
|
| - views::MouseWatcherViewHost* host =
|
| - new views::MouseWatcherViewHost(browser_view_, insets);
|
| - // MouseWatcher takes ownership of |host|.
|
| - mouse_watcher_.reset(new views::MouseWatcher(host, this));
|
| - mouse_watcher_->set_notify_on_exit_time(
|
| - base::TimeDelta::FromMilliseconds(kHideDelayMs));
|
| - mouse_watcher_->Start();
|
| }
|
|
|
| // ui::EventHandler overrides:
|
| @@ -91,12 +169,14 @@ ui::EventResult ImmersiveModeController::OnKeyEvent(ui::KeyEvent* event) {
|
| }
|
|
|
| ui::EventResult ImmersiveModeController::OnMouseEvent(ui::MouseEvent* event) {
|
| + if (event->type() != ui::ET_MOUSE_MOVED)
|
| + return ui::ER_UNHANDLED;
|
| if (event->location().y() == 0) {
|
| // Use a timer to detect if the cursor stays at the top past a delay.
|
| if (!top_timer_.IsRunning()) {
|
| top_timer_.Start(FROM_HERE,
|
| base::TimeDelta::FromMilliseconds(kRevealDelayMs),
|
| - this, &ImmersiveModeController::RevealTopViews);
|
| + this, &ImmersiveModeController::StartReveal);
|
| }
|
| } else {
|
| // Cursor left the top edge.
|
| @@ -121,10 +201,102 @@ ui::EventResult ImmersiveModeController::OnGestureEvent(
|
|
|
| // views::MouseWatcherListener overrides:
|
| void ImmersiveModeController::MouseMovedOutOfHost() {
|
| - // Stop watching the mouse.
|
| + EndReveal(true);
|
| +}
|
| +
|
| +// ui::ImplicitAnimationObserver overrides:
|
| +void ImmersiveModeController::OnImplicitAnimationsCompleted() {
|
| + // Fired when the slide-out animation completes.
|
| + ResetRevealView();
|
| +}
|
| +
|
| +// Testing interface:
|
| +void ImmersiveModeController::StartRevealForTest() {
|
| + StartReveal();
|
| +}
|
| +
|
| +void ImmersiveModeController::EndRevealForTest() {
|
| + EndReveal(false);
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +// private:
|
| +
|
| +void ImmersiveModeController::StartReveal() {
|
| + if (revealed_)
|
| + return;
|
| + revealed_ = true;
|
| +
|
| + // Recompute the bounds of the views when painted normally.
|
| + browser_view_->tabstrip()->SetImmersiveStyle(false);
|
| + browser_view_->Layout();
|
| +
|
| + // Place tabstrip, toolbar, and bookmarks bar in a new view at the end of
|
| + // the BrowserView hierarchy so it paints over the web contents.
|
| + reveal_view_.reset(new RevealView(browser_view_));
|
| + browser_view_->AddChildView(reveal_view_.get());
|
| + reveal_view_->AcquireTopViews();
|
| +
|
| + // Slide in the reveal view.
|
| + AnimateShowRevealView();
|
| +
|
| + // Stop the immersive reveal when the mouse leaves the top-of-window area.
|
| + StartMouseWatcher();
|
| +}
|
| +
|
| +void ImmersiveModeController::AnimateShowRevealView() {
|
| + DCHECK(reveal_view_.get());
|
| + gfx::Transform transform;
|
| + transform.Translate(0, -reveal_view_->height());
|
| + reveal_view_->SetTransform(transform);
|
| +
|
| + ui::ScopedLayerAnimationSettings settings(
|
| + reveal_view_->layer()->GetAnimator());
|
| + settings.SetTweenType(ui::Tween::EASE_OUT);
|
| + reveal_view_->SetTransform(gfx::Transform());
|
| +}
|
| +
|
| +void ImmersiveModeController::StartMouseWatcher() {
|
| + DCHECK(reveal_view_.get());
|
| + views::MouseWatcherViewHost* host =
|
| + new views::MouseWatcherViewHost(reveal_view_.get(), gfx::Insets());
|
| + // MouseWatcher takes ownership of |host|.
|
| + mouse_watcher_.reset(new views::MouseWatcher(host, this));
|
| + mouse_watcher_->set_notify_on_exit_time(
|
| + base::TimeDelta::FromMilliseconds(kHideDelayMs));
|
| + mouse_watcher_->Start();
|
| +}
|
| +
|
| +void ImmersiveModeController::EndReveal(bool animate) {
|
| + revealed_ = false;
|
| mouse_watcher_.reset();
|
| - // Stop showing the top views.
|
| - hide_top_views_ = true;
|
| - browser_view_->tabstrip()->SetImmersiveStyle(true);
|
| +
|
| + if (reveal_view_.get()) {
|
| + reveal_view_->ReleaseTopViews();
|
| + if (animate) {
|
| + // Animation resets the reveal view when complete.
|
| + AnimateHideRevealView();
|
| + } else {
|
| + ResetRevealView();
|
| + }
|
| + }
|
| +
|
| + browser_view_->tabstrip()->SetImmersiveStyle(enabled_);
|
| browser_view_->Layout();
|
| }
|
| +
|
| +void ImmersiveModeController::AnimateHideRevealView() {
|
| + ui::Layer* layer = reveal_view_->layer();
|
| + ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
|
| + settings.SetTweenType(ui::Tween::EASE_OUT);
|
| + settings.AddObserver(this); // Resets |reveal_view_| on completion.
|
| + gfx::Transform transform;
|
| + transform.Translate(0, -layer->bounds().height());
|
| + layer->SetTransform(transform);
|
| +}
|
| +
|
| +void ImmersiveModeController::ResetRevealView() {
|
| + browser_view_->RemoveChildView(reveal_view_.get());
|
| + reveal_view_.reset();
|
| +}
|
| +
|
|
|