Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(358)

Side by Side Diff: chrome/browser/ui/views/immersive_mode_controller.cc

Issue 11411250: Immersive mode reveals the tabstrip/omnibox on top of web content (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix window close Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/views/immersive_mode_controller.h" 5 #include "chrome/browser/ui/views/immersive_mode_controller.h"
6 6
7 #include "chrome/browser/ui/views/frame/browser_frame.h"
7 #include "chrome/browser/ui/views/frame/browser_view.h" 8 #include "chrome/browser/ui/views/frame/browser_view.h"
8 #include "chrome/browser/ui/views/frame/contents_container.h" 9 #include "chrome/browser/ui/views/frame/contents_container.h"
9 #include "chrome/browser/ui/views/tabs/tab_strip.h" 10 #include "chrome/browser/ui/views/tabs/tab_strip.h"
11 #include "chrome/browser/ui/views/toolbar_view.h"
12 #include "ui/compositor/scoped_layer_animation_settings.h"
13 #include "ui/gfx/transform.h"
10 #include "ui/views/mouse_watcher_view_host.h" 14 #include "ui/views/mouse_watcher_view_host.h"
15 #include "ui/views/view.h"
16 #include "ui/views/window/non_client_view.h"
11 17
12 #if defined(USE_AURA) 18 #if defined(USE_AURA)
13 #include "ui/aura/window.h" 19 #include "ui/aura/window.h"
14 #endif 20 #endif
15 21
16 namespace { 22 namespace {
17 23
18 // Time after which the edge trigger fires and top-chrome is revealed. 24 // Time after which the edge trigger fires and top-chrome is revealed.
19 const int kRevealDelayMs = 200; 25 const int kRevealDelayMs = 200;
20 26
21 // During an immersive-mode top-of-window reveal, how long to wait after the 27 // During an immersive-mode top-of-window reveal, how long to wait after the
22 // mouse exits the views before hiding them again. 28 // mouse exits the views before hiding them again.
23 const int kHideDelayMs = 200; 29 const int kHideDelayMs = 200;
24 30
25 } // namespace 31 } // namespace
26 32
33 ////////////////////////////////////////////////////////////////////////////////
34
35 // View to hold the tab strip, toolbar, and sometimes the bookmark bar during
36 // an immersive mode reveal. Paints on top of other layers in order to appear
37 // over the web contents. Immersive mode uses this view to avoid changing the
38 // BrowserView's view structure in the steady state.
39 // TODO(jamescook): If immersive mode becomes non-experimental, use a permanent
40 // top-of-window container view in BrowserView instead of RevealView to avoid
41 // reparenting.
42 // TODO(jamescook): Bookmark bar does not yet work.
43 class RevealView : public views::View {
44 public:
45 explicit RevealView(BrowserView* browser_view);
46 virtual ~RevealView();
47
48 // Reparents the |browser_view_| tab strip, toolbar, and bookmark bar to
49 // this view.
50 void AcquireTopViews();
51
52 // Reparents tab strip, toolbar, and bookmark bar back to |browser_view_|.
53 void ReleaseTopViews();
54
55 // views::View overrides:
56 virtual void PaintChildren(gfx::Canvas* canvas) OVERRIDE;
57
58 private:
59 // None of these views are owned.
60 BrowserView* browser_view_;
61 TabStrip* tabstrip_;
62 ToolbarView* toolbar_view_;
63
64 DISALLOW_COPY_AND_ASSIGN(RevealView);
65 };
66
67 RevealView::RevealView(BrowserView* browser_view)
68 : browser_view_(browser_view),
69 tabstrip_(NULL),
70 toolbar_view_(NULL) {
71 SetPaintToLayer(true);
72 SetFillsBoundsOpaquely(true);
73 }
74
75 RevealView::~RevealView() {}
76
77 void RevealView::AcquireTopViews() {
78 // Reparenting causes hit tests that require a parent for |this|.
79 DCHECK(parent());
80
81 tabstrip_ = browser_view_->tabstrip();
82 toolbar_view_ = browser_view_->GetToolbarView();
83
84 // Ensure the indices are what we expect before we start moving the views.
85 DCHECK_EQ(browser_view_->GetIndexOf(tabstrip_), BrowserView::kTabstripIndex);
86 DCHECK_EQ(browser_view_->GetIndexOf(toolbar_view_),
87 BrowserView::kToolbarIndex);
88
89 AddChildView(tabstrip_);
90 AddChildView(toolbar_view_);
91
92 // Set our initial bounds, which triggers a Layout().
93 int width = parent()->width();
94 int height = toolbar_view_->bounds().bottom();
95 SetBounds(0, 0, width, height);
96 }
97
98 void RevealView::ReleaseTopViews() {
99 // Reparenting causes hit tests that require a parent for |this|.
100 DCHECK(parent());
101
102 browser_view_->AddChildViewAt(tabstrip_, BrowserView::kTabstripIndex);
103 browser_view_->AddChildViewAt(toolbar_view_, BrowserView::kToolbarIndex);
104
105 // Ensure the newly restored views get painted.
106 tabstrip_->SchedulePaint();
107 toolbar_view_->SchedulePaint();
108
109 tabstrip_ = NULL;
110 toolbar_view_ = NULL;
111 }
112
113 void RevealView::PaintChildren(gfx::Canvas* canvas) {
114 // Top-views depend on parts of the frame (themes, window buttons) being
115 // painted underneath them. Clip rect has already been set to the bounds
116 // of this view, so just paint the frame.
117 views::View* frame = browser_view_->frame()->GetFrameView();
118 frame->Paint(canvas);
sky 2012/11/29 19:30:23 Won't this try to paint all the children of the fr
James Cook 2012/11/29 21:20:59 I need all the children of the frame view to be pa
119
120 views::View::PaintChildren(canvas);
121 }
122
123 ////////////////////////////////////////////////////////////////////////////////
124
27 ImmersiveModeController::ImmersiveModeController(BrowserView* browser_view) 125 ImmersiveModeController::ImmersiveModeController(BrowserView* browser_view)
28 : browser_view_(browser_view), 126 : browser_view_(browser_view),
29 enabled_(false), 127 enabled_(false),
30 hide_top_views_(false) { 128 revealed_(false) {
31 } 129 }
32 130
33 ImmersiveModeController::~ImmersiveModeController() {} 131 ImmersiveModeController::~ImmersiveModeController() {
132 // Ensure views are reparented if we are deleted mid-reveal.
133 if (reveal_view_.get()) {
134 reveal_view_->ReleaseTopViews();
135 ResetRevealView();
136 }
137 }
34 138
35 void ImmersiveModeController::SetEnabled(bool enabled) { 139 void ImmersiveModeController::SetEnabled(bool enabled) {
36 if (enabled_ == enabled) 140 if (enabled_ == enabled)
37 return; 141 return;
38 enabled_ = enabled; 142 enabled_ = enabled;
39 hide_top_views_ = enabled; 143
40 browser_view_->tabstrip()->SetImmersiveStyle(enabled_); 144 if (enabled_) {
41 browser_view_->Layout(); 145 browser_view_->tabstrip()->SetImmersiveStyle(true);
146 browser_view_->Layout();
147 } else {
148 // Don't Layout() browser_view_ because EndReveal() does so.
149 EndReveal(false);
150 top_timer_.Stop();
151 }
42 152
43 #if defined(USE_AURA) 153 #if defined(USE_AURA)
44 // TODO(jamescook): If we want to port this feature to non-Aura views we'll 154 // TODO(jamescook): If we want to port this feature to non-Aura views we'll
45 // need a method to monitor incoming mouse move events without handling them. 155 // need a method to monitor incoming mouse move events without handling them.
46 // Currently views uses GetEventHandlerForPoint() to route events directly 156 // Currently views uses GetEventHandlerForPoint() to route events directly
47 // to either a tab or the caption area, bypassing pre-target handlers and 157 // to either a tab or the caption area, bypassing pre-target handlers and
48 // intermediate views. 158 // intermediate views.
49 if (enabled_) 159 if (enabled_)
50 browser_view_->GetNativeWindow()->AddPreTargetHandler(this); 160 browser_view_->GetNativeWindow()->AddPreTargetHandler(this);
51 else 161 else
52 browser_view_->GetNativeWindow()->RemovePreTargetHandler(this); 162 browser_view_->GetNativeWindow()->RemovePreTargetHandler(this);
53 #endif // defined(USE_AURA) 163 #endif // defined(USE_AURA)
54
55 if (!enabled_) {
56 // Stop watching the mouse on disable.
57 mouse_watcher_.reset();
58 top_timer_.Stop();
59 }
60 }
61
62 void ImmersiveModeController::RevealTopViews() {
63 if (!hide_top_views_)
64 return;
65 hide_top_views_ = false;
66
67 // Recompute the bounds of the views when painted normally.
68 browser_view_->tabstrip()->SetImmersiveStyle(false);
69 browser_view_->Layout();
70
71 // Compute the top of the content area in order to find the bottom of all
72 // the top-of-window views like toolbar, bookmarks, etc.
73 gfx::Point content_origin(0, 0);
74 views::View::ConvertPointToTarget(
75 browser_view_->contents(), browser_view_, &content_origin);
76
77 // Stop the immersive reveal when the mouse leaves the top-of-window area.
78 gfx::Insets insets(0, 0, content_origin.y() - browser_view_->height(), 0);
79 views::MouseWatcherViewHost* host =
80 new views::MouseWatcherViewHost(browser_view_, insets);
81 // MouseWatcher takes ownership of |host|.
82 mouse_watcher_.reset(new views::MouseWatcher(host, this));
83 mouse_watcher_->set_notify_on_exit_time(
84 base::TimeDelta::FromMilliseconds(kHideDelayMs));
85 mouse_watcher_->Start();
86 } 164 }
87 165
88 // ui::EventHandler overrides: 166 // ui::EventHandler overrides:
89 ui::EventResult ImmersiveModeController::OnKeyEvent(ui::KeyEvent* event) { 167 ui::EventResult ImmersiveModeController::OnKeyEvent(ui::KeyEvent* event) {
90 return ui::ER_UNHANDLED; 168 return ui::ER_UNHANDLED;
91 } 169 }
92 170
93 ui::EventResult ImmersiveModeController::OnMouseEvent(ui::MouseEvent* event) { 171 ui::EventResult ImmersiveModeController::OnMouseEvent(ui::MouseEvent* event) {
172 if (event->type() != ui::ET_MOUSE_MOVED)
173 return ui::ER_UNHANDLED;
94 if (event->location().y() == 0) { 174 if (event->location().y() == 0) {
95 // Use a timer to detect if the cursor stays at the top past a delay. 175 // Use a timer to detect if the cursor stays at the top past a delay.
96 if (!top_timer_.IsRunning()) { 176 if (!top_timer_.IsRunning()) {
97 top_timer_.Start(FROM_HERE, 177 top_timer_.Start(FROM_HERE,
98 base::TimeDelta::FromMilliseconds(kRevealDelayMs), 178 base::TimeDelta::FromMilliseconds(kRevealDelayMs),
99 this, &ImmersiveModeController::RevealTopViews); 179 this, &ImmersiveModeController::StartReveal);
100 } 180 }
101 } else { 181 } else {
102 // Cursor left the top edge. 182 // Cursor left the top edge.
103 top_timer_.Stop(); 183 top_timer_.Stop();
104 } 184 }
105 // Pass along event for further handling. 185 // Pass along event for further handling.
106 return ui::ER_UNHANDLED; 186 return ui::ER_UNHANDLED;
107 } 187 }
108 188
109 ui::EventResult ImmersiveModeController::OnScrollEvent(ui::ScrollEvent* event) { 189 ui::EventResult ImmersiveModeController::OnScrollEvent(ui::ScrollEvent* event) {
110 return ui::ER_UNHANDLED; 190 return ui::ER_UNHANDLED;
111 } 191 }
112 192
113 ui::EventResult ImmersiveModeController::OnTouchEvent(ui::TouchEvent* event) { 193 ui::EventResult ImmersiveModeController::OnTouchEvent(ui::TouchEvent* event) {
114 return ui::ER_UNHANDLED; 194 return ui::ER_UNHANDLED;
115 } 195 }
116 196
117 ui::EventResult ImmersiveModeController::OnGestureEvent( 197 ui::EventResult ImmersiveModeController::OnGestureEvent(
118 ui::GestureEvent* event) { 198 ui::GestureEvent* event) {
119 return ui::ER_UNHANDLED; 199 return ui::ER_UNHANDLED;
120 } 200 }
121 201
122 // views::MouseWatcherListener overrides: 202 // views::MouseWatcherListener overrides:
123 void ImmersiveModeController::MouseMovedOutOfHost() { 203 void ImmersiveModeController::MouseMovedOutOfHost() {
124 // Stop watching the mouse. 204 EndReveal(true);
205 }
206
207 // ui::ImplicitAnimationObserver overrides:
208 void ImmersiveModeController::OnImplicitAnimationsCompleted() {
209 // Fired when the slide-out animation completes.
210 ResetRevealView();
211 }
212
213 // Testing interface:
214 void ImmersiveModeController::StartRevealForTest() {
215 StartReveal();
216 }
217
218 void ImmersiveModeController::EndRevealForTest() {
219 EndReveal(false);
220 }
221
222 ////////////////////////////////////////////////////////////////////////////////
223 // private:
224
225 void ImmersiveModeController::StartReveal() {
226 if (revealed_)
227 return;
228 revealed_ = true;
229
230 // Recompute the bounds of the views when painted normally.
231 browser_view_->tabstrip()->SetImmersiveStyle(false);
232 browser_view_->Layout();
233
234 // Place tabstrip, toolbar, and bookmarks bar in a new view at the end of
235 // the BrowserView hierarchy so it paints over the web contents.
236 reveal_view_.reset(new RevealView(browser_view_));
237 browser_view_->AddChildView(reveal_view_.get());
238 reveal_view_->AcquireTopViews();
239
240 // Slide in the reveal view.
241 AnimateShowRevealView();
242
243 // Stop the immersive reveal when the mouse leaves the top-of-window area.
244 StartMouseWatcher();
245 }
246
247 void ImmersiveModeController::AnimateShowRevealView() {
248 DCHECK(reveal_view_.get());
249 gfx::Transform transform;
250 transform.Translate(0, -reveal_view_->height());
251 reveal_view_->SetTransform(transform);
252
253 ui::ScopedLayerAnimationSettings settings(
254 reveal_view_->layer()->GetAnimator());
255 settings.SetTweenType(ui::Tween::EASE_OUT);
256 reveal_view_->SetTransform(gfx::Transform());
257 }
258
259 void ImmersiveModeController::StartMouseWatcher() {
260 DCHECK(reveal_view_.get());
261 views::MouseWatcherViewHost* host =
262 new views::MouseWatcherViewHost(reveal_view_.get(), gfx::Insets());
263 // MouseWatcher takes ownership of |host|.
264 mouse_watcher_.reset(new views::MouseWatcher(host, this));
265 mouse_watcher_->set_notify_on_exit_time(
266 base::TimeDelta::FromMilliseconds(kHideDelayMs));
267 mouse_watcher_->Start();
268 }
269
270 void ImmersiveModeController::EndReveal(bool animate) {
271 revealed_ = false;
125 mouse_watcher_.reset(); 272 mouse_watcher_.reset();
126 // Stop showing the top views. 273
127 hide_top_views_ = true; 274 if (reveal_view_.get()) {
128 browser_view_->tabstrip()->SetImmersiveStyle(true); 275 reveal_view_->ReleaseTopViews();
276 if (animate) {
277 // Animation resets the reveal view when complete.
278 AnimateHideRevealView();
279 } else {
280 ResetRevealView();
281 }
282 }
283
284 browser_view_->tabstrip()->SetImmersiveStyle(enabled_);
129 browser_view_->Layout(); 285 browser_view_->Layout();
130 } 286 }
287
288 void ImmersiveModeController::AnimateHideRevealView() {
289 ui::Layer* layer = reveal_view_->layer();
290 ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
291 settings.SetTweenType(ui::Tween::EASE_OUT);
292 settings.AddObserver(this); // Resets |reveal_view_| on completion.
293 gfx::Transform transform;
294 transform.Translate(0, -layer->bounds().height());
295 layer->SetTransform(transform);
296 }
297
298 void ImmersiveModeController::ResetRevealView() {
299 browser_view_->RemoveChildView(reveal_view_.get());
300 reveal_view_.reset();
301 }
302
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698