OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "athena/wm/window_overview_mode.h" | 5 #include "athena/wm/window_overview_mode.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <functional> | 8 #include <functional> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
11 #include "base/bind.h" | |
11 #include "base/macros.h" | 12 #include "base/macros.h" |
12 #include "ui/aura/scoped_window_targeter.h" | 13 #include "ui/aura/scoped_window_targeter.h" |
13 #include "ui/aura/window.h" | 14 #include "ui/aura/window.h" |
14 #include "ui/aura/window_delegate.h" | 15 #include "ui/aura/window_delegate.h" |
15 #include "ui/aura/window_property.h" | 16 #include "ui/aura/window_property.h" |
16 #include "ui/aura/window_targeter.h" | 17 #include "ui/aura/window_targeter.h" |
17 #include "ui/aura/window_tree_host.h" | 18 #include "ui/aura/window_tree_host.h" |
18 #include "ui/compositor/compositor.h" | 19 #include "ui/compositor/compositor.h" |
19 #include "ui/compositor/compositor_animation_observer.h" | 20 #include "ui/compositor/compositor_animation_observer.h" |
20 #include "ui/compositor/scoped_layer_animation_settings.h" | 21 #include "ui/compositor/scoped_layer_animation_settings.h" |
21 #include "ui/events/event_handler.h" | 22 #include "ui/events/event_handler.h" |
22 #include "ui/events/gestures/fling_curve.h" | 23 #include "ui/events/gestures/fling_curve.h" |
23 #include "ui/gfx/frame_time.h" | 24 #include "ui/gfx/frame_time.h" |
24 #include "ui/gfx/transform.h" | 25 #include "ui/gfx/transform.h" |
26 #include "ui/gfx/transform_util.h" | |
25 #include "ui/wm/core/shadow.h" | 27 #include "ui/wm/core/shadow.h" |
26 | 28 |
27 namespace { | 29 namespace { |
28 | 30 |
29 struct WindowOverviewState { | 31 struct WindowOverviewState { |
30 // The transform for when the window is at the topmost position. | 32 // The transform for when the window is at the topmost position. |
31 gfx::Transform top; | 33 gfx::Transform top; |
32 | 34 |
33 // The transform for when the window is at the bottom-most position. | 35 // The transform for when the window is at the bottom-most position. |
34 gfx::Transform bottom; | 36 gfx::Transform bottom; |
35 | 37 |
36 // The current overview state of the window. 0.f means the window is at the | 38 // The current overview state of the window. 0.f means the window is at the |
37 // topmost position. 1.f means the window is at the bottom-most position. | 39 // topmost position. 1.f means the window is at the bottom-most position. |
38 float progress; | 40 float progress; |
39 | 41 |
40 scoped_ptr<wm::Shadow> shadow; | 42 scoped_ptr<wm::Shadow> shadow; |
41 }; | 43 }; |
42 | 44 |
45 // Runs a callback at the end of the animation. This observe also destroys | |
46 // itself afterwards. | |
47 class ClosureAnimationObserver : public ui::ImplicitAnimationObserver { | |
48 public: | |
49 explicit ClosureAnimationObserver(const base::Closure& closure) | |
50 : closure_(closure) {} | |
Jun Mukai
2014/08/07 21:00:30
Can you add DCHECK(!closure.is_null()) here?
Your
sadrul
2014/08/07 21:15:36
Done.
| |
51 private: | |
52 virtual ~ClosureAnimationObserver() { | |
53 } | |
54 | |
55 // ui::ImplicitAnimationObserver: | |
56 virtual void OnImplicitAnimationsCompleted() OVERRIDE { | |
57 if (!closure_.is_null()) | |
58 closure_.Run(); | |
59 delete this; | |
60 } | |
61 | |
62 base::Closure closure_; | |
63 | |
64 DISALLOW_COPY_AND_ASSIGN(ClosureAnimationObserver); | |
65 }; | |
66 | |
43 } // namespace | 67 } // namespace |
44 | 68 |
45 DECLARE_WINDOW_PROPERTY_TYPE(WindowOverviewState*) | 69 DECLARE_WINDOW_PROPERTY_TYPE(WindowOverviewState*) |
46 DEFINE_OWNED_WINDOW_PROPERTY_KEY(WindowOverviewState, | 70 DEFINE_OWNED_WINDOW_PROPERTY_KEY(WindowOverviewState, |
47 kWindowOverviewState, | 71 kWindowOverviewState, |
48 NULL) | 72 NULL) |
49 namespace athena { | 73 namespace athena { |
50 | 74 |
51 namespace { | 75 namespace { |
52 | 76 |
53 bool ShouldShowWindowInOverviewMode(aura::Window* window) { | 77 bool ShouldShowWindowInOverviewMode(aura::Window* window) { |
54 return window->type() == ui::wm::WINDOW_TYPE_NORMAL; | 78 return window->type() == ui::wm::WINDOW_TYPE_NORMAL; |
55 } | 79 } |
56 | 80 |
81 // Gets the transform for the window in its current state. | |
82 gfx::Transform GetTransformForState(WindowOverviewState* state) { | |
83 return gfx::Tween::TransformValueBetween(state->progress, | |
84 state->top, | |
85 state->bottom); | |
86 } | |
87 | |
57 // Sets the progress-state for the window in the overview mode. | 88 // Sets the progress-state for the window in the overview mode. |
58 void SetWindowProgress(aura::Window* window, float progress) { | 89 void SetWindowProgress(aura::Window* window, float progress) { |
59 WindowOverviewState* state = window->GetProperty(kWindowOverviewState); | 90 WindowOverviewState* state = window->GetProperty(kWindowOverviewState); |
60 gfx::Transform transform = | |
61 gfx::Tween::TransformValueBetween(progress, state->top, state->bottom); | |
62 window->SetTransform(transform); | |
63 state->progress = progress; | 91 state->progress = progress; |
92 window->SetTransform(GetTransformForState(state)); | |
64 } | 93 } |
65 | 94 |
66 // Resets the overview-related state for |window|. | 95 // Resets the overview-related state for |window|. |
67 void RestoreWindowState(aura::Window* window) { | 96 void RestoreWindowState(aura::Window* window) { |
68 window->ClearProperty(kWindowOverviewState); | 97 window->ClearProperty(kWindowOverviewState); |
69 | 98 |
70 ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator()); | 99 ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator()); |
71 settings.SetPreemptionStrategy( | 100 settings.SetPreemptionStrategy( |
72 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | 101 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
73 settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(250)); | 102 settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(250)); |
(...skipping 27 matching lines...) Expand all Loading... | |
101 public ui::EventHandler, | 130 public ui::EventHandler, |
102 public ui::CompositorAnimationObserver { | 131 public ui::CompositorAnimationObserver { |
103 public: | 132 public: |
104 WindowOverviewModeImpl(aura::Window* container, | 133 WindowOverviewModeImpl(aura::Window* container, |
105 WindowOverviewModeDelegate* delegate) | 134 WindowOverviewModeDelegate* delegate) |
106 : container_(container), | 135 : container_(container), |
107 delegate_(delegate), | 136 delegate_(delegate), |
108 scoped_targeter_(new aura::ScopedWindowTargeter( | 137 scoped_targeter_(new aura::ScopedWindowTargeter( |
109 container, | 138 container, |
110 scoped_ptr<ui::EventTargeter>( | 139 scoped_ptr<ui::EventTargeter>( |
111 new StaticWindowTargeter(container)))) { | 140 new StaticWindowTargeter(container)))), |
141 dragged_window_(NULL) { | |
112 container_->set_target_handler(this); | 142 container_->set_target_handler(this); |
113 | 143 |
114 // Prepare the desired transforms for all the windows, and set the initial | 144 // Prepare the desired transforms for all the windows, and set the initial |
115 // state on the windows. | 145 // state on the windows. |
116 ComputeTerminalStatesForAllWindows(); | 146 ComputeTerminalStatesForAllWindows(); |
117 SetInitialWindowStates(); | 147 SetInitialWindowStates(); |
118 } | 148 } |
119 | 149 |
120 virtual ~WindowOverviewModeImpl() { | 150 virtual ~WindowOverviewModeImpl() { |
121 container_->set_target_handler(container_->delegate()); | 151 container_->set_target_handler(container_->delegate()); |
(...skipping 14 matching lines...) Expand all Loading... | |
136 void ComputeTerminalStatesForAllWindows() { | 166 void ComputeTerminalStatesForAllWindows() { |
137 const aura::Window::Windows& windows = container_->children(); | 167 const aura::Window::Windows& windows = container_->children(); |
138 size_t window_count = std::count_if(windows.begin(), windows.end(), | 168 size_t window_count = std::count_if(windows.begin(), windows.end(), |
139 ShouldShowWindowInOverviewMode); | 169 ShouldShowWindowInOverviewMode); |
140 | 170 |
141 size_t index = 0; | 171 size_t index = 0; |
142 const gfx::Size container_size = container_->bounds().size(); | 172 const gfx::Size container_size = container_->bounds().size(); |
143 | 173 |
144 const int kGapBetweenWindowsBottom = 10; | 174 const int kGapBetweenWindowsBottom = 10; |
145 const int kGapBetweenWindowsTop = 5; | 175 const int kGapBetweenWindowsTop = 5; |
146 const float kMinScale = 0.6f; | |
147 const float kMaxScale = 0.95f; | |
148 | 176 |
149 for (aura::Window::Windows::const_reverse_iterator iter = windows.rbegin(); | 177 for (aura::Window::Windows::const_reverse_iterator iter = windows.rbegin(); |
150 iter != windows.rend(); | 178 iter != windows.rend(); |
151 ++iter) { | 179 ++iter) { |
152 aura::Window* window = (*iter); | 180 aura::Window* window = (*iter); |
153 if (!ShouldShowWindowInOverviewMode(window)) | 181 if (!ShouldShowWindowInOverviewMode(window)) |
154 continue; | 182 continue; |
155 | 183 |
156 gfx::Transform top_transform; | 184 gfx::Transform top_transform; |
157 int top = (window_count - index - 1) * kGapBetweenWindowsTop; | 185 int top = (window_count - index - 1) * kGapBetweenWindowsTop; |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
304 if (!compositor->HasAnimationObserver(this)) | 332 if (!compositor->HasAnimationObserver(this)) |
305 compositor->AddAnimationObserver(this); | 333 compositor->AddAnimationObserver(this); |
306 } | 334 } |
307 | 335 |
308 void RemoveAnimationObserver() { | 336 void RemoveAnimationObserver() { |
309 ui::Compositor* compositor = container_->GetHost()->compositor(); | 337 ui::Compositor* compositor = container_->GetHost()->compositor(); |
310 if (compositor->HasAnimationObserver(this)) | 338 if (compositor->HasAnimationObserver(this)) |
311 compositor->RemoveAnimationObserver(this); | 339 compositor->RemoveAnimationObserver(this); |
312 } | 340 } |
313 | 341 |
342 void DragWindow(const ui::GestureEvent& event) { | |
343 CHECK(dragged_window_); | |
344 CHECK_EQ(ui::ET_GESTURE_SCROLL_UPDATE, event.type()); | |
345 gfx::Vector2dF dragged_distance = | |
346 dragged_start_location_ - event.location(); | |
347 WindowOverviewState* dragged_state = | |
348 dragged_window_->GetProperty(kWindowOverviewState); | |
349 CHECK(dragged_state); | |
350 gfx::Transform transform = GetTransformForState(dragged_state); | |
351 transform.Translate(-dragged_distance.x(), 0); | |
352 dragged_window_->SetTransform(transform); | |
353 | |
354 float ratio = std::min( | |
355 1.f, std::abs(dragged_distance.x()) / kMinDistanceForDismissal); | |
356 float opacity = | |
357 gfx::Tween::FloatValueBetween(ratio, kMaxOpacity, kMinOpacity); | |
358 dragged_window_->layer()->SetOpacity(opacity); | |
359 } | |
360 | |
361 bool ShouldCloseDragWindow(const ui::GestureEvent& event) const { | |
362 gfx::Vector2dF dragged_distance = | |
363 dragged_start_location_ - event.location(); | |
364 if (event.type() == ui::ET_GESTURE_SCROLL_END) | |
365 return std::abs(dragged_distance.x()) >= kMinDistanceForDismissal; | |
366 CHECK_EQ(ui::ET_SCROLL_FLING_START, event.type()); | |
367 const bool dragging_towards_right = dragged_distance.x() < 0; | |
368 const bool swipe_towards_right = event.details().velocity_x() > 0; | |
369 if (dragging_towards_right != swipe_towards_right) | |
370 return false; | |
371 const float kMinVelocityForDismissal = 500.f; | |
372 return std::abs(event.details().velocity_x()) > kMinVelocityForDismissal; | |
373 } | |
374 | |
375 void CloseDragWindow(const ui::GestureEvent& gesture) { | |
376 // Animate |dragged_window_| offscreen first, then destroy it. | |
377 ui::ScopedLayerAnimationSettings settings( | |
378 dragged_window_->layer()->GetAnimator()); | |
379 settings.SetPreemptionStrategy( | |
380 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | |
381 settings.AddObserver(new ClosureAnimationObserver( | |
382 base::Bind(&base::DeletePointer<aura::Window>, dragged_window_))); | |
383 | |
384 WindowOverviewState* dragged_state = | |
385 dragged_window_->GetProperty(kWindowOverviewState); | |
386 CHECK(dragged_state); | |
387 gfx::Transform transform = dragged_window_->layer()->transform(); | |
388 gfx::RectF transformed_bounds = dragged_window_->bounds(); | |
389 transform.TransformRect(&transformed_bounds); | |
390 float transform_x = 0.f; | |
391 if (gesture.location().x() > dragged_start_location_.x()) | |
392 transform_x = container_->bounds().right() - transformed_bounds.x(); | |
393 else | |
394 transform_x = -(transformed_bounds.x() + transformed_bounds.width()); | |
395 float scale = gfx::Tween::FloatValueBetween( | |
396 dragged_state->progress, kMinScale, kMaxScale); | |
397 transform.Translate(transform_x / scale, 0); | |
398 dragged_window_->SetTransform(transform); | |
399 dragged_window_->layer()->SetOpacity(kMinOpacity); | |
400 | |
401 // Move the windows behind |dragged_window_| in the stack forward one step. | |
402 const aura::Window::Windows& list = container_->children(); | |
403 aura::Window::Windows::const_reverse_iterator find = | |
404 std::find(list.rbegin(), list.rend(), dragged_window_); | |
405 CHECK(list.rend() != find); | |
406 float progress = (*find)->GetProperty(kWindowOverviewState)->progress; | |
407 for (++find; find != list.rend(); ++find) { | |
408 aura::Window* window = *find; | |
409 ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator()); | |
410 settings.SetPreemptionStrategy( | |
411 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | |
412 float next_progress = window->GetProperty(kWindowOverviewState)->progress; | |
413 SetWindowProgress(window, progress); | |
414 progress = next_progress; | |
415 } | |
416 | |
417 dragged_window_ = NULL; | |
418 } | |
419 | |
420 void RestoreDragWindow() { | |
421 CHECK(dragged_window_); | |
422 WindowOverviewState* dragged_state = | |
423 dragged_window_->GetProperty(kWindowOverviewState); | |
424 CHECK(dragged_state); | |
425 | |
426 ui::ScopedLayerAnimationSettings settings( | |
427 dragged_window_->layer()->GetAnimator()); | |
428 settings.SetPreemptionStrategy( | |
429 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | |
430 dragged_window_->SetTransform(GetTransformForState(dragged_state)); | |
431 dragged_window_->layer()->SetOpacity(1.f); | |
Jun Mukai
2014/08/07 21:00:30
should reset dragged_window_ here?
sadrul
2014/08/07 21:15:36
Done.
| |
432 } | |
433 | |
314 // ui::EventHandler: | 434 // ui::EventHandler: |
315 virtual void OnMouseEvent(ui::MouseEvent* mouse) OVERRIDE { | 435 virtual void OnMouseEvent(ui::MouseEvent* mouse) OVERRIDE { |
316 if (mouse->type() == ui::ET_MOUSE_PRESSED) { | 436 if (mouse->type() == ui::ET_MOUSE_PRESSED) { |
317 aura::Window* select = SelectWindowAt(mouse); | 437 aura::Window* select = SelectWindowAt(mouse); |
318 if (select) { | 438 if (select) { |
319 mouse->SetHandled(); | 439 mouse->SetHandled(); |
320 delegate_->OnSelectWindow(select); | 440 delegate_->OnSelectWindow(select); |
321 } | 441 } |
322 } else if (mouse->type() == ui::ET_MOUSEWHEEL) { | 442 } else if (mouse->type() == ui::ET_MOUSEWHEEL) { |
323 DoScroll(static_cast<ui::MouseWheelEvent*>(mouse)->y_offset()); | 443 DoScroll(static_cast<ui::MouseWheelEvent*>(mouse)->y_offset()); |
324 } | 444 } |
325 } | 445 } |
326 | 446 |
327 virtual void OnScrollEvent(ui::ScrollEvent* scroll) OVERRIDE { | 447 virtual void OnScrollEvent(ui::ScrollEvent* scroll) OVERRIDE { |
328 if (scroll->type() == ui::ET_SCROLL) | 448 if (scroll->type() == ui::ET_SCROLL) |
329 DoScroll(scroll->y_offset()); | 449 DoScroll(scroll->y_offset()); |
330 } | 450 } |
331 | 451 |
332 virtual void OnGestureEvent(ui::GestureEvent* gesture) OVERRIDE { | 452 virtual void OnGestureEvent(ui::GestureEvent* gesture) OVERRIDE { |
333 if (gesture->type() == ui::ET_GESTURE_TAP) { | 453 if (gesture->type() == ui::ET_GESTURE_TAP) { |
334 aura::Window* select = SelectWindowAt(gesture); | 454 aura::Window* select = SelectWindowAt(gesture); |
335 if (select) { | 455 if (select) { |
336 gesture->SetHandled(); | 456 gesture->SetHandled(); |
337 delegate_->OnSelectWindow(select); | 457 delegate_->OnSelectWindow(select); |
338 } | 458 } |
459 } else if (gesture->type() == ui::ET_GESTURE_SCROLL_BEGIN) { | |
460 if (std::abs(gesture->details().scroll_x_hint()) > | |
461 std::abs(gesture->details().scroll_y_hint()) * 2) { | |
462 dragged_start_location_ = gesture->location(); | |
463 dragged_window_ = SelectWindowAt(gesture); | |
464 } | |
339 } else if (gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) { | 465 } else if (gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) { |
340 DoScroll(gesture->details().scroll_y()); | 466 if (dragged_window_) |
467 DragWindow(*gesture); | |
468 else | |
469 DoScroll(gesture->details().scroll_y()); | |
470 gesture->SetHandled(); | |
471 } else if (gesture->type() == ui::ET_GESTURE_SCROLL_END) { | |
472 if (dragged_window_) { | |
473 if (ShouldCloseDragWindow(*gesture)) | |
474 CloseDragWindow(*gesture); | |
475 else | |
476 RestoreDragWindow(); | |
477 } | |
341 gesture->SetHandled(); | 478 gesture->SetHandled(); |
342 } else if (gesture->type() == ui::ET_SCROLL_FLING_START) { | 479 } else if (gesture->type() == ui::ET_SCROLL_FLING_START) { |
343 CreateFlingerFor(*gesture); | 480 if (dragged_window_) { |
344 AddAnimationObserver(); | 481 if (ShouldCloseDragWindow(*gesture)) |
482 CloseDragWindow(*gesture); | |
483 else | |
484 RestoreDragWindow(); | |
485 } else { | |
486 CreateFlingerFor(*gesture); | |
487 AddAnimationObserver(); | |
488 } | |
345 gesture->SetHandled(); | 489 gesture->SetHandled(); |
346 } else if (gesture->type() == ui::ET_GESTURE_TAP_DOWN && fling_) { | 490 } else if (gesture->type() == ui::ET_GESTURE_TAP_DOWN) { |
347 fling_.reset(); | 491 if (fling_) { |
348 RemoveAnimationObserver(); | 492 fling_.reset(); |
349 gesture->SetHandled(); | 493 RemoveAnimationObserver(); |
494 gesture->SetHandled(); | |
495 } | |
496 dragged_window_ = NULL; | |
350 } | 497 } |
351 } | 498 } |
352 | 499 |
353 // ui::CompositorAnimationObserver: | 500 // ui::CompositorAnimationObserver: |
354 virtual void OnAnimationStep(base::TimeTicks timestamp) OVERRIDE { | 501 virtual void OnAnimationStep(base::TimeTicks timestamp) OVERRIDE { |
355 CHECK(fling_); | 502 CHECK(fling_); |
356 if (fling_->start_timestamp() > timestamp) | 503 if (fling_->start_timestamp() > timestamp) |
357 return; | 504 return; |
358 gfx::Vector2dF scroll = fling_->GetScrollAmountAtTime(timestamp); | 505 gfx::Vector2dF scroll = fling_->GetScrollAmountAtTime(timestamp); |
359 if (scroll.IsZero()) { | 506 if (scroll.IsZero()) { |
360 fling_.reset(); | 507 fling_.reset(); |
361 RemoveAnimationObserver(); | 508 RemoveAnimationObserver(); |
362 } else { | 509 } else { |
363 DoScroll(scroll.y()); | 510 DoScroll(scroll.y()); |
364 } | 511 } |
365 } | 512 } |
366 | 513 |
514 const int kMinDistanceForDismissal = 300; | |
515 const float kMinScale = 0.6f; | |
516 const float kMaxScale = 0.95f; | |
517 const float kMaxOpacity = 1.0f; | |
518 const float kMinOpacity = 0.2f; | |
519 | |
367 aura::Window* container_; | 520 aura::Window* container_; |
368 WindowOverviewModeDelegate* delegate_; | 521 WindowOverviewModeDelegate* delegate_; |
369 scoped_ptr<aura::ScopedWindowTargeter> scoped_targeter_; | 522 scoped_ptr<aura::ScopedWindowTargeter> scoped_targeter_; |
370 scoped_ptr<ui::FlingCurve> fling_; | 523 scoped_ptr<ui::FlingCurve> fling_; |
371 | 524 |
525 aura::Window* dragged_window_; | |
526 gfx::Point dragged_start_location_; | |
527 | |
372 DISALLOW_COPY_AND_ASSIGN(WindowOverviewModeImpl); | 528 DISALLOW_COPY_AND_ASSIGN(WindowOverviewModeImpl); |
373 }; | 529 }; |
374 | 530 |
375 } // namespace | 531 } // namespace |
376 | 532 |
377 // static | 533 // static |
378 scoped_ptr<WindowOverviewMode> WindowOverviewMode::Create( | 534 scoped_ptr<WindowOverviewMode> WindowOverviewMode::Create( |
379 aura::Window* container, | 535 aura::Window* container, |
380 WindowOverviewModeDelegate* delegate) { | 536 WindowOverviewModeDelegate* delegate) { |
381 return scoped_ptr<WindowOverviewMode>( | 537 return scoped_ptr<WindowOverviewMode>( |
382 new WindowOverviewModeImpl(container, delegate)); | 538 new WindowOverviewModeImpl(container, delegate)); |
383 } | 539 } |
384 | 540 |
385 } // namespace athena | 541 } // namespace athena |
OLD | NEW |