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
3 // found in the LICENSE file.
5 #include "athena/wm/window_overview_mode.h"
11 #include "athena/wm/overview_toolbar.h"
12 #include "athena/wm/public/window_list_provider.h"
13 #include "athena/wm/public/window_list_provider_observer.h"
14 #include "athena/wm/split_view_controller.h"
15 #include "base/bind.h"
16 #include "base/macros.h"
17 #include "ui/aura/scoped_window_targeter.h"
18 #include "ui/aura/window.h"
19 #include "ui/aura/window_delegate.h"
20 #include "ui/aura/window_property.h"
21 #include "ui/aura/window_targeter.h"
22 #include "ui/aura/window_tree_host.h"
23 #include "ui/compositor/closure_animation_observer.h"
24 #include "ui/compositor/compositor.h"
25 #include "ui/compositor/compositor_animation_observer.h"
26 #include "ui/compositor/scoped_layer_animation_settings.h"
27 #include "ui/events/event_handler.h"
28 #include "ui/events/gestures/fling_curve.h"
29 #include "ui/gfx/frame_time.h"
30 #include "ui/gfx/transform.h"
31 #include "ui/wm/core/shadow_types.h"
32 #include "ui/wm/core/window_animations.h"
33 #include "ui/wm/core/window_util.h"
37 const float kOverviewDefaultScale = 0.75f;
39 struct WindowOverviewState {
40 // The current overview state of the window. 0.f means the window is at the
41 // topmost position. 1.f means the window is at the bottom-most position.
44 // The top-most and bottom-most vertical position of the window in overview
49 // |split| is set if this window is one of the two split windows in split-view
56 DECLARE_WINDOW_PROPERTY_TYPE(WindowOverviewState*)
57 DEFINE_OWNED_WINDOW_PROPERTY_KEY(WindowOverviewState,
64 gfx::Transform GetTransformForSplitWindow(aura::Window* window, float scale) {
65 const float kScrollWindowPositionInOverview = 0.65f;
66 int x_translate = window->bounds().width() * (1 - scale) / 2;
67 gfx::Transform transform;
69 x_translate, window->bounds().height() * kScrollWindowPositionInOverview);
70 transform.Scale(scale, scale);
74 // Gets the transform for the window in its current state.
75 gfx::Transform GetTransformForState(aura::Window* window,
76 WindowOverviewState* state) {
78 return GetTransformForSplitWindow(window, kOverviewDefaultScale);
80 const float kProgressToStartShrinking = 0.07;
81 const float kOverviewScale = 0.75f;
82 float scale = kOverviewScale;
83 if (state->progress < kProgressToStartShrinking) {
84 const float kShrunkMinimumScale = 0.7f;
85 scale = gfx::Tween::FloatValueBetween(
86 state->progress / kProgressToStartShrinking,
90 int container_width = window->parent()->bounds().width();
91 int window_width = window->bounds().width();
92 int window_x = window->bounds().x();
93 float x_translate = (container_width - (window_width * scale)) / 2 - window_x;
94 float y_translate = gfx::Tween::FloatValueBetween(
95 state->progress, state->min_y, state->max_y);
96 gfx::Transform transform;
97 transform.Translate(x_translate, y_translate);
98 transform.Scale(scale, scale);
102 // Sets the progress-state for the window in the overview mode.
103 void SetWindowProgress(aura::Window* window, float progress) {
104 WindowOverviewState* state = window->GetProperty(kWindowOverviewState);
105 state->progress = progress;
107 gfx::Transform transform = GetTransformForState(window, state);
108 window->SetTransform(transform);
111 void HideWindowIfNotVisible(aura::Window* window,
112 SplitViewController* split_view_controller) {
113 bool should_hide = true;
114 if (split_view_controller->IsSplitViewModeActive()) {
115 should_hide = window != split_view_controller->left_window() &&
116 window != split_view_controller->right_window();
118 should_hide = !wm::IsActiveWindow(window);
124 // Resets the overview-related state for |window|.
125 void RestoreWindowState(aura::Window* window,
126 SplitViewController* split_view_controller) {
127 window->ClearProperty(kWindowOverviewState);
129 ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
130 settings.SetPreemptionStrategy(
131 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
132 settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(250));
134 settings.AddObserver(new ui::ClosureAnimationObserver(
135 base::Bind(&HideWindowIfNotVisible, window, split_view_controller)));
137 window->SetTransform(gfx::Transform());
139 // Reset the window opacity in case the user is dragging a window.
140 window->layer()->SetOpacity(1.0f);
142 wm::SetShadowType(window, wm::SHADOW_TYPE_NONE);
145 gfx::RectF GetTransformedBounds(aura::Window* window) {
146 gfx::Transform transform;
147 gfx::RectF bounds = window->bounds();
148 transform.Translate(bounds.x(), bounds.y());
149 transform.PreconcatTransform(window->layer()->transform());
150 transform.Translate(-bounds.x(), -bounds.y());
151 transform.TransformRect(&bounds);
155 void TransformSplitWindowScale(aura::Window* window, float scale) {
156 gfx::Transform transform = window->layer()->GetTargetTransform();
157 if (transform.Scale2d() == gfx::Vector2dF(scale, scale))
159 ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
160 window->SetTransform(GetTransformForSplitWindow(window, scale));
163 void AnimateWindowTo(aura::Window* animate_window,
164 aura::Window* target_window) {
165 ui::ScopedLayerAnimationSettings settings(
166 animate_window->layer()->GetAnimator());
167 settings.SetPreemptionStrategy(
168 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
169 WindowOverviewState* target_state =
170 target_window->GetProperty(kWindowOverviewState);
171 SetWindowProgress(animate_window, target_state->progress);
174 // Always returns the same target.
175 class StaticWindowTargeter : public aura::WindowTargeter {
177 explicit StaticWindowTargeter(aura::Window* target) : target_(target) {}
178 virtual ~StaticWindowTargeter() {}
181 // aura::WindowTargeter:
182 virtual ui::EventTarget* FindTargetForEvent(ui::EventTarget* root,
183 ui::Event* event) OVERRIDE {
187 virtual ui::EventTarget* FindTargetForLocatedEvent(
188 ui::EventTarget* root,
189 ui::LocatedEvent* event) OVERRIDE {
193 aura::Window* target_;
194 DISALLOW_COPY_AND_ASSIGN(StaticWindowTargeter);
197 class WindowOverviewModeImpl : public WindowOverviewMode,
198 public ui::EventHandler,
199 public ui::CompositorAnimationObserver,
200 public WindowListProviderObserver {
202 WindowOverviewModeImpl(aura::Window* container,
203 WindowListProvider* window_list_provider,
204 SplitViewController* split_view_controller,
205 WindowOverviewModeDelegate* delegate)
206 : container_(container),
207 window_list_provider_(window_list_provider),
208 split_view_controller_(split_view_controller),
210 scoped_targeter_(new aura::ScopedWindowTargeter(
212 scoped_ptr<ui::EventTargeter>(
213 new StaticWindowTargeter(container)))),
214 dragged_window_(NULL) {
216 container_->set_target_handler(this);
218 // Prepare the desired transforms for all the windows, and set the initial
219 // state on the windows.
220 ComputeTerminalStatesForAllWindows();
221 SetInitialWindowStates();
223 window_list_provider_->AddObserver(this);
226 virtual ~WindowOverviewModeImpl() {
227 window_list_provider_->RemoveObserver(this);
228 container_->set_target_handler(container_->delegate());
229 RemoveAnimationObserver();
230 const aura::Window::Windows& windows =
231 window_list_provider_->GetWindowList();
234 std::for_each(windows.begin(),
236 std::bind2nd(std::ptr_fun(&RestoreWindowState),
237 split_view_controller_));
241 // Computes the transforms for all windows in both the topmost and bottom-most
242 // positions. The transforms are set in the |kWindowOverviewState| property of
244 void ComputeTerminalStatesForAllWindows() {
247 const aura::Window::Windows& windows =
248 window_list_provider_->GetWindowList();
249 for (aura::Window::Windows::const_reverse_iterator iter = windows.rbegin();
250 iter != windows.rend();
252 aura::Window* window = (*iter);
253 wm::SetShadowType(window, wm::SHADOW_TYPE_RECTANGULAR_ALWAYS_ACTIVE);
255 WindowOverviewState* state = new WindowOverviewState;
256 window->SetProperty(kWindowOverviewState, state);
257 if (split_view_controller_->IsSplitViewModeActive() &&
258 (window == split_view_controller_->left_window() ||
259 window == split_view_controller_->right_window())) {
260 // Do not let the left/right windows be scrolled.
261 gfx::Transform transform =
262 GetTransformForSplitWindow(window, kOverviewDefaultScale);
263 state->max_y = state->min_y = transform.To2dTranslation().y();
268 state->split = false;
269 UpdateTerminalStateForWindowAtIndex(window, index, windows.size());
273 // Computes the terminal states (i.e. the transforms for the top-most and
274 // bottom-most position in the stack) for |window|. |window_count| is the
275 // number of windows in the stack, and |index| is the position of the window
276 // in the stack (0 being the front-most window).
277 void UpdateTerminalStateForWindowAtIndex(aura::Window* window,
279 size_t window_count) {
280 const int kGapBetweenWindowsBottom = 10;
281 const int kGapBetweenWindowsTop = 5;
283 int top = (window_count - index - 1) * kGapBetweenWindowsTop;
284 int bottom = GetScrollableHeight() - (index * kGapBetweenWindowsBottom);
286 WindowOverviewState* state = window->GetProperty(kWindowOverviewState);
291 state->max_y = bottom - window->bounds().y();
292 state->progress = 0.f;
295 // Sets the initial position for the windows for the overview mode.
296 void SetInitialWindowStates() {
297 // The initial overview state of the topmost three windows.
298 const float kInitialProgress[] = { 0.5f, 0.05f, 0.01f };
300 const aura::Window::Windows& windows =
301 window_list_provider_->GetWindowList();
302 for (aura::Window::Windows::const_reverse_iterator iter = windows.rbegin();
303 iter != windows.rend();
305 float progress = 0.f;
306 aura::Window* window = *iter;
307 if (split_view_controller_->IsSplitViewModeActive() &&
308 (window == split_view_controller_->left_window() ||
309 window == split_view_controller_->right_window())) {
312 if (index < arraysize(kInitialProgress))
313 progress = kInitialProgress[index];
317 scoped_refptr<ui::LayerAnimator> animator =
318 window->layer()->GetAnimator();
320 // Unset any in-progress animation.
321 animator->AbortAllAnimations();
323 window->SetTransform(gfx::Transform());
324 // Setup the animation.
326 ui::ScopedLayerAnimationSettings settings(animator);
327 settings.SetPreemptionStrategy(
328 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
329 settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(250));
330 SetWindowProgress(window, progress);
335 aura::Window* SelectWindowAt(ui::LocatedEvent* event) {
336 CHECK_EQ(container_, event->target());
337 // Find the old targeter to find the target of the event.
338 ui::EventTarget* window = container_;
339 ui::EventTargeter* targeter = scoped_targeter_->old_targeter();
340 while (!targeter && window->GetParentTarget()) {
341 window = window->GetParentTarget();
342 targeter = window->GetEventTargeter();
346 aura::Window* target = static_cast<aura::Window*>(
347 targeter->FindTargetForLocatedEvent(container_, event));
348 while (target && target->parent() != container_)
349 target = target->parent();
353 // Scroll the window list by |delta_y| amount. |delta_y| is negative when
354 // scrolling up; and positive when scrolling down.
355 void DoScroll(float delta_y) {
356 const float kEpsilon = 1e-3f;
357 float delta_y_p = std::abs(delta_y) / GetScrollableHeight();
358 const aura::Window::Windows& windows =
359 window_list_provider_->GetWindowList();
361 // Scroll up. Start with the top-most (i.e. behind-most in terms of
362 // z-index) window, and try to scroll them up.
363 for (aura::Window::Windows::const_iterator iter = windows.begin();
364 delta_y_p > kEpsilon && iter != windows.end();
366 aura::Window* window = (*iter);
367 WindowOverviewState* state = window->GetProperty(kWindowOverviewState);
368 if (state->progress > kEpsilon) {
369 // It is possible to scroll |window| up. Scroll it up, and update
370 // |delta_y_p| for the next window.
371 float apply = delta_y_p * state->progress;
372 SetWindowProgress(window, std::max(0.f, state->progress - apply * 3));
377 // Scroll down. Start with the bottom-most (i.e. front-most in terms of
378 // z-index) window, and try to scroll them down.
379 aura::Window::Windows::const_reverse_iterator iter;
380 for (iter = windows.rbegin();
381 delta_y_p > kEpsilon && iter != windows.rend();
383 aura::Window* window = (*iter);
384 WindowOverviewState* state = window->GetProperty(kWindowOverviewState);
385 if (1.f - state->progress > kEpsilon) {
386 // It is possible to scroll |window| down. Scroll it down, and update
387 // |delta_y_p| for the next window.
388 SetWindowProgress(window, std::min(1.f, state->progress + delta_y_p));
395 int GetScrollableHeight() const {
396 const float kScrollableFraction = 0.85f;
397 const float kScrollableFractionInSplit = 0.5f;
398 const float fraction = split_view_controller_->IsSplitViewModeActive()
399 ? kScrollableFractionInSplit
400 : kScrollableFraction;
401 return container_->bounds().height() * fraction;
404 void CreateFlingerFor(const ui::GestureEvent& event) {
405 gfx::Vector2dF velocity(event.details().velocity_x(),
406 event.details().velocity_y());
407 fling_.reset(new ui::FlingCurve(velocity, gfx::FrameTime::Now()));
410 void AddAnimationObserver() {
411 ui::Compositor* compositor = container_->GetHost()->compositor();
412 if (!compositor->HasAnimationObserver(this))
413 compositor->AddAnimationObserver(this);
416 void RemoveAnimationObserver() {
417 ui::Compositor* compositor = container_->GetHost()->compositor();
418 if (compositor->HasAnimationObserver(this))
419 compositor->RemoveAnimationObserver(this);
422 aura::Window* GetSplitWindowDropTarget(const ui::GestureEvent& event) const {
423 if (!split_view_controller_->IsSplitViewModeActive())
425 CHECK(dragged_window_);
426 CHECK_NE(split_view_controller_->left_window(), dragged_window_);
427 CHECK_NE(split_view_controller_->right_window(), dragged_window_);
428 aura::Window* window = split_view_controller_->left_window();
429 if (GetTransformedBounds(window).Contains(event.location()))
431 window = split_view_controller_->right_window();
432 if (GetTransformedBounds(window).Contains(event.location()))
437 void DragWindow(const ui::GestureEvent& event) {
438 CHECK(dragged_window_);
439 CHECK_EQ(ui::ET_GESTURE_SCROLL_UPDATE, event.type());
440 CHECK(overview_toolbar_);
441 gfx::Vector2dF dragged_distance =
442 dragged_start_location_ - event.location();
443 WindowOverviewState* dragged_state =
444 dragged_window_->GetProperty(kWindowOverviewState);
445 CHECK(dragged_state);
446 gfx::Transform transform =
447 GetTransformForState(dragged_window_, dragged_state);
448 transform.Translate(-dragged_distance.x(), 0);
449 dragged_window_->SetTransform(transform);
451 // Update the toolbar.
452 const int kMinDistanceForActionButtons = 20;
453 if (fabs(dragged_distance.x()) > kMinDistanceForActionButtons)
454 overview_toolbar_->ShowActionButtons();
456 overview_toolbar_->HideActionButtons();
458 // See if the touch-point is above one of the action-buttons.
459 OverviewToolbar::ActionType new_action =
460 overview_toolbar_->GetHighlightAction(event);
462 // If the touch-point is not above any of the action buttons, then highlight
463 // the close-button by default, if the user has dragged enough to close the
465 if (new_action == OverviewToolbar::ACTION_TYPE_NONE) {
466 if (fabs(dragged_distance.x()) > kMinDistanceForDismissal)
467 new_action = OverviewToolbar::ACTION_TYPE_CLOSE;
469 new_action = OverviewToolbar::ACTION_TYPE_NONE;
471 OverviewToolbar::ActionType previous_action =
472 overview_toolbar_->current_action();
473 overview_toolbar_->SetHighlightAction(new_action);
475 aura::Window* split_drop = GetSplitWindowDropTarget(event);
477 // If the user has selected to get into split-view mode, then show the
478 // window with full opacity. Otherwise, fade it out as it closes. Animate
479 // the opacity if transitioning to/from the split-view button.
480 bool animate_opacity =
481 (new_action != previous_action) &&
482 ((new_action == OverviewToolbar::ACTION_TYPE_SPLIT) ||
483 (previous_action == OverviewToolbar::ACTION_TYPE_SPLIT));
484 float ratio = std::min(
485 1.f, std::abs(dragged_distance.x()) / kMinDistanceForDismissal);
487 (new_action == OverviewToolbar::ACTION_TYPE_SPLIT || split_drop)
489 : gfx::Tween::FloatValueBetween(ratio, kMaxOpacity, kMinOpacity);
490 if (animate_opacity) {
491 ui::ScopedLayerAnimationSettings settings(
492 dragged_window_->layer()->GetAnimator());
493 dragged_window_->layer()->SetOpacity(opacity);
495 dragged_window_->layer()->SetOpacity(opacity);
498 if (split_view_controller_->IsSplitViewModeActive()) {
499 float scale = kOverviewDefaultScale;
500 if (split_drop == split_view_controller_->left_window())
501 scale = kMaxScaleForSplitTarget;
502 TransformSplitWindowScale(split_view_controller_->left_window(), scale);
504 scale = kOverviewDefaultScale;
505 if (split_drop == split_view_controller_->right_window())
506 scale = kMaxScaleForSplitTarget;
507 TransformSplitWindowScale(split_view_controller_->right_window(), scale);
511 bool ShouldCloseDragWindow(const ui::GestureEvent& event) const {
512 gfx::Vector2dF dragged_distance =
513 dragged_start_location_ - event.location();
514 if (event.type() == ui::ET_GESTURE_SCROLL_END)
515 return std::abs(dragged_distance.x()) >= kMinDistanceForDismissal;
516 CHECK_EQ(ui::ET_SCROLL_FLING_START, event.type());
517 const bool dragging_towards_right = dragged_distance.x() < 0;
518 const bool swipe_towards_right = event.details().velocity_x() > 0;
519 if (dragging_towards_right != swipe_towards_right)
521 const float kMinVelocityForDismissal = 500.f;
522 return std::abs(event.details().velocity_x()) > kMinVelocityForDismissal;
525 void CloseDragWindow(const ui::GestureEvent& gesture) {
526 // Animate |dragged_window_| offscreen first, then destroy it.
528 wm::ScopedHidingAnimationSettings settings(dragged_window_);
529 settings.layer_animation_settings()->SetPreemptionStrategy(
530 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
532 WindowOverviewState* dragged_state =
533 dragged_window_->GetProperty(kWindowOverviewState);
534 CHECK(dragged_state);
535 gfx::Transform transform = dragged_window_->layer()->transform();
536 gfx::RectF transformed_bounds = dragged_window_->bounds();
537 transform.TransformRect(&transformed_bounds);
538 float transform_x = 0.f;
539 if (gesture.location().x() > dragged_start_location_.x())
540 transform_x = container_->bounds().right() - transformed_bounds.x();
542 transform_x = -(transformed_bounds.x() + transformed_bounds.width());
543 transform.Translate(transform_x / kOverviewDefaultScale, 0);
544 dragged_window_->SetTransform(transform);
545 dragged_window_->layer()->SetOpacity(kMinOpacity);
547 delete dragged_window_;
548 dragged_window_ = NULL;
551 void RestoreDragWindow() {
552 CHECK(dragged_window_);
553 WindowOverviewState* dragged_state =
554 dragged_window_->GetProperty(kWindowOverviewState);
555 CHECK(dragged_state);
557 ui::ScopedLayerAnimationSettings settings(
558 dragged_window_->layer()->GetAnimator());
559 settings.SetPreemptionStrategy(
560 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
561 dragged_window_->SetTransform(
562 GetTransformForState(dragged_window_, dragged_state));
563 dragged_window_->layer()->SetOpacity(1.f);
564 dragged_window_ = NULL;
567 void EndDragWindow(const ui::GestureEvent& gesture) {
568 CHECK(dragged_window_);
569 CHECK(overview_toolbar_);
570 OverviewToolbar::ActionType action = overview_toolbar_->current_action();
571 overview_toolbar_.reset();
572 if (action == OverviewToolbar::ACTION_TYPE_SPLIT) {
573 delegate_->OnSelectSplitViewWindow(NULL,
579 // If the window is dropped on one of the left/right windows in split-mode,
580 // then switch that window.
581 aura::Window* split_drop = GetSplitWindowDropTarget(gesture);
583 aura::Window* left = split_view_controller_->left_window();
584 aura::Window* right = split_view_controller_->right_window();
585 if (left == split_drop)
586 left = dragged_window_;
588 right = dragged_window_;
589 delegate_->OnSelectSplitViewWindow(left, right, dragged_window_);
593 if (ShouldCloseDragWindow(gesture))
594 CloseDragWindow(gesture);
599 void SelectWindow(aura::Window* window) {
600 if (!split_view_controller_->IsSplitViewModeActive()) {
601 delegate_->OnSelectWindow(window);
603 // If the selected window is one of the left/right windows, then keep the
605 if (window == split_view_controller_->left_window() ||
606 window == split_view_controller_->right_window()) {
607 delegate_->OnSelectSplitViewWindow(
608 split_view_controller_->left_window(),
609 split_view_controller_->right_window(),
612 delegate_->OnSelectWindow(window);
618 virtual void OnMouseEvent(ui::MouseEvent* mouse) OVERRIDE {
619 if (mouse->type() == ui::ET_MOUSE_PRESSED) {
620 aura::Window* select = SelectWindowAt(mouse);
623 SelectWindow(select);
625 } else if (mouse->type() == ui::ET_MOUSEWHEEL) {
626 DoScroll(static_cast<ui::MouseWheelEvent*>(mouse)->y_offset());
630 virtual void OnScrollEvent(ui::ScrollEvent* scroll) OVERRIDE {
631 if (scroll->type() == ui::ET_SCROLL)
632 DoScroll(scroll->y_offset());
635 virtual void OnGestureEvent(ui::GestureEvent* gesture) OVERRIDE {
636 if (gesture->type() == ui::ET_GESTURE_TAP) {
637 aura::Window* select = SelectWindowAt(gesture);
639 gesture->SetHandled();
640 SelectWindow(select);
642 } else if (gesture->type() == ui::ET_GESTURE_SCROLL_BEGIN) {
643 if (std::abs(gesture->details().scroll_x_hint()) >
644 std::abs(gesture->details().scroll_y_hint()) * 2) {
645 dragged_start_location_ = gesture->location();
646 dragged_window_ = SelectWindowAt(gesture);
647 if (split_view_controller_->IsSplitViewModeActive() &&
648 (dragged_window_ == split_view_controller_->left_window() ||
649 dragged_window_ == split_view_controller_->right_window())) {
650 // TODO(sad): Allow closing the left/right window. Closing one of
651 // these windows will terminate the split-view mode. Until then, do
652 // not allow closing these (since otherwise it gets into an undefined
654 dragged_window_ = NULL;
657 if (dragged_window_) {
658 // Show the toolbar (for closing a window, or going into split-view
659 // mode). If already in split-view mode, then do not show the 'Split'
661 overview_toolbar_.reset(new OverviewToolbar(container_));
662 if (!split_view_controller_->CanActivateSplitViewMode()) {
663 overview_toolbar_->DisableAction(
664 OverviewToolbar::ACTION_TYPE_SPLIT);
668 } else if (gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
670 DragWindow(*gesture);
672 DoScroll(gesture->details().scroll_y());
673 gesture->SetHandled();
674 } else if (gesture->type() == ui::ET_GESTURE_SCROLL_END) {
676 EndDragWindow(*gesture);
677 gesture->SetHandled();
678 } else if (gesture->type() == ui::ET_SCROLL_FLING_START) {
679 if (dragged_window_) {
680 EndDragWindow(*gesture);
682 CreateFlingerFor(*gesture);
683 AddAnimationObserver();
685 gesture->SetHandled();
686 } else if (gesture->type() == ui::ET_GESTURE_TAP_DOWN) {
689 RemoveAnimationObserver();
690 gesture->SetHandled();
692 dragged_window_ = NULL;
696 // ui::CompositorAnimationObserver:
697 virtual void OnAnimationStep(base::TimeTicks timestamp) OVERRIDE {
699 if (fling_->start_timestamp() > timestamp)
701 gfx::Vector2dF scroll = fling_->GetScrollAmountAtTime(timestamp);
702 if (scroll.IsZero()) {
704 RemoveAnimationObserver();
706 DoScroll(scroll.y());
710 // WindowListProviderObserver:
711 virtual void OnWindowStackingChanged() OVERRIDE {
712 // Recompute the states of all windows. There isn't enough information at
713 // this point to do anything more clever.
714 ComputeTerminalStatesForAllWindows();
715 SetInitialWindowStates();
718 virtual void OnWindowRemoved(aura::Window* removed_window,
719 int index) OVERRIDE {
720 const aura::Window::Windows& windows =
721 window_list_provider_->GetWindowList();
724 CHECK_LE(index, static_cast<int>(windows.size()));
726 // The back-most window has been removed. Move all the remaining windows
727 // one step backwards.
728 for (int i = windows.size() - 1; i > 0; --i) {
729 UpdateTerminalStateForWindowAtIndex(
730 windows[i], windows.size() - 1 - i, windows.size());
731 AnimateWindowTo(windows[i], windows[i - 1]);
733 UpdateTerminalStateForWindowAtIndex(windows.front(),
736 AnimateWindowTo(windows.front(), removed_window);
738 // Move all windows behind the removed window one step forwards.
739 for (int i = 0; i < index - 1; ++i) {
740 UpdateTerminalStateForWindowAtIndex(windows[i], windows.size() - 1 - i,
742 AnimateWindowTo(windows[i], windows[i + 1]);
744 UpdateTerminalStateForWindowAtIndex(windows[index - 1],
745 windows.size() - index,
747 AnimateWindowTo(windows[index - 1], removed_window);
751 const int kMinDistanceForDismissal = 300;
752 const float kMaxOpacity = 1.0f;
753 const float kMinOpacity = 0.2f;
754 const float kMaxScaleForSplitTarget = 0.9f;
756 aura::Window* container_;
757 // Provider of the stack of windows to show in the overview mode. Not owned.
758 WindowListProvider* window_list_provider_;
759 SplitViewController* split_view_controller_;
761 WindowOverviewModeDelegate* delegate_;
762 scoped_ptr<aura::ScopedWindowTargeter> scoped_targeter_;
763 scoped_ptr<ui::FlingCurve> fling_;
765 aura::Window* dragged_window_;
766 gfx::Point dragged_start_location_;
767 scoped_ptr<OverviewToolbar> overview_toolbar_;
769 DISALLOW_COPY_AND_ASSIGN(WindowOverviewModeImpl);
775 scoped_ptr<WindowOverviewMode> WindowOverviewMode::Create(
776 aura::Window* container,
777 WindowListProvider* window_list_provider,
778 SplitViewController* split_view_controller,
779 WindowOverviewModeDelegate* delegate) {
780 return scoped_ptr<WindowOverviewMode>(
781 new WindowOverviewModeImpl(container, window_list_provider,
782 split_view_controller, delegate));
785 } // namespace athena