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"
10 #include "athena/util/athena_constants.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/memory/scoped_vector.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"
34 #include "ui/wm/public/activation_client.h"
38 struct WindowOverviewState
{
39 // The current overview state of the window. 0.f means the window is at the
40 // topmost position. 1.f means the window is at the bottom-most position.
43 // The top-most and bottom-most vertical position of the window in overview
48 // |split| is set if this window is one of the two split windows in split-view
55 DECLARE_WINDOW_PROPERTY_TYPE(WindowOverviewState
*);
56 DEFINE_OWNED_WINDOW_PROPERTY_KEY(WindowOverviewState
,
64 const float kOverviewDefaultScale
= 0.75f
;
66 gfx::Transform
GetTransformForSplitWindow(aura::Window
* window
, float scale
) {
67 const float kScrollWindowPositionInOverview
= 0.65f
;
68 int x_translate
= window
->bounds().width() * (1 - scale
) / 2;
69 gfx::Transform transform
;
71 x_translate
, window
->bounds().height() * kScrollWindowPositionInOverview
);
72 transform
.Scale(scale
, scale
);
76 // Gets the transform for the window in its current state.
77 gfx::Transform
GetTransformForState(aura::Window
* window
,
78 WindowOverviewState
* state
) {
80 return GetTransformForSplitWindow(window
, kOverviewDefaultScale
);
82 const float kProgressToStartShrinking
= 0.07;
83 const float kOverviewScale
= 0.75f
;
84 float scale
= kOverviewScale
;
85 if (state
->progress
< kProgressToStartShrinking
) {
86 const float kShrunkMinimumScale
= 0.7f
;
87 scale
= gfx::Tween::FloatValueBetween(
88 state
->progress
/ kProgressToStartShrinking
,
92 int container_width
= window
->parent()->bounds().width();
93 int window_width
= window
->bounds().width();
94 int window_x
= window
->bounds().x();
95 float x_translate
= (container_width
- (window_width
* scale
)) / 2 - window_x
;
96 float y_translate
= gfx::Tween::FloatValueBetween(
97 state
->progress
, state
->min_y
, state
->max_y
);
98 gfx::Transform transform
;
99 transform
.Translate(x_translate
, y_translate
);
100 transform
.Scale(scale
, scale
);
104 // A utility class used to set the transform/opacity to the window and
105 // its transient children.
106 class TransientGroupSetter
{
108 explicit TransientGroupSetter(aura::Window
* window
) : window_(window
) {
110 ~TransientGroupSetter() {}
112 // Aborts all animations including its transient children.
113 void AbortAllAnimations() {
114 window_
->layer()->GetAnimator()->AbortAllAnimations();
115 for (aura::Window
* transient_child
: wm::GetTransientChildren(window_
))
116 transient_child
->layer()->GetAnimator()->AbortAllAnimations();
119 // Applys transform to the window and its transient children.
120 // Transient children gets a tranfrorm with the offset relateive
121 // it its transient parent.
122 void SetTransform(const gfx::Transform
& transform
) {
123 window_
->SetTransform(transform
);
124 for (aura::Window
* transient_child
: wm::GetTransientChildren(window_
)) {
125 gfx::Rect window_bounds
= window_
->bounds();
126 gfx::Rect child_bounds
= transient_child
->bounds();
127 gfx::Transform
transient_window_transform(TranslateTransformOrigin(
128 child_bounds
.origin() - window_bounds
.origin(), transform
));
129 transient_child
->SetTransform(transient_window_transform
);
133 // Sets the opacity to the window and its transient children.
134 void SetOpacity(float opacity
) {
135 window_
->layer()->SetOpacity(opacity
);
136 for (aura::Window
* transient_child
: wm::GetTransientChildren(window_
)) {
137 transient_child
->layer()->SetOpacity(opacity
);
141 // Apply the transform with the overview scroll |progress|.
142 void SetWindowProgress(float progress
) {
143 WindowOverviewState
* state
= window_
->GetProperty(kWindowOverviewState
);
144 state
->progress
= progress
;
146 SetTransform(GetTransformForState(window_
, state
));
150 static gfx::Transform
TranslateTransformOrigin(
151 const gfx::Vector2d
& new_origin
,
152 const gfx::Transform
& transform
) {
153 gfx::Transform result
;
154 result
.Translate(-new_origin
.x(), -new_origin
.y());
155 result
.PreconcatTransform(transform
);
156 result
.Translate(new_origin
.x(), new_origin
.y());
160 aura::Window
* window_
;
162 DISALLOW_COPY_AND_ASSIGN(TransientGroupSetter
);
165 // TransientGroupSetter with animation.
166 class AnimateTransientGroupSetter
: public TransientGroupSetter
{
168 explicit AnimateTransientGroupSetter(aura::Window
* window
)
169 : TransientGroupSetter(window
) {
170 animation_settings_
.push_back(CreateScopedLayerAnimationSettings(window
));
171 for (aura::Window
* transient_child
: wm::GetTransientChildren(window
)) {
172 animation_settings_
.push_back(
173 CreateScopedLayerAnimationSettings(transient_child
));
176 ~AnimateTransientGroupSetter() {}
178 ui::ScopedLayerAnimationSettings
* GetMainWindowAnimationSettings() {
179 CHECK(animation_settings_
.size());
180 return animation_settings_
[0];
184 static ui::ScopedLayerAnimationSettings
* CreateScopedLayerAnimationSettings(
185 aura::Window
* window
) {
186 const int kTransitionMs
= 250;
188 ui::ScopedLayerAnimationSettings
* settings
=
189 new ui::ScopedLayerAnimationSettings(window
->layer()->GetAnimator());
190 settings
->SetPreemptionStrategy(
191 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET
);
192 settings
->SetTransitionDuration(
193 base::TimeDelta::FromMilliseconds(kTransitionMs
));
197 ScopedVector
<ui::ScopedLayerAnimationSettings
> animation_settings_
;
198 DISALLOW_COPY_AND_ASSIGN(AnimateTransientGroupSetter
);
201 void HideWindowIfNotVisible(aura::Window
* window
,
202 SplitViewController
* split_view_controller
) {
203 bool should_hide
= true;
204 if (split_view_controller
->IsSplitViewModeActive()) {
205 should_hide
= window
!= split_view_controller
->left_window() &&
206 window
!= split_view_controller
->right_window();
208 aura::Window
* active
= aura::client::GetActivationClient(
209 window
->GetRootWindow())->GetActiveWindow();
210 should_hide
= active
!= window
&& wm::GetTransientParent(active
) != window
;
216 // Resets the overview-related state for |window|.
217 void RestoreWindowState(aura::Window
* window
,
218 SplitViewController
* split_view_controller
) {
219 window
->ClearProperty(kWindowOverviewState
);
221 AnimateTransientGroupSetter
setter(window
);
223 setter
.GetMainWindowAnimationSettings()->AddObserver(
224 new ui::ClosureAnimationObserver(
225 base::Bind(&HideWindowIfNotVisible
, window
, split_view_controller
)));
227 setter
.SetTransform(gfx::Transform());
228 // Reset the window opacity in case the user is dragging a window.
229 setter
.SetOpacity(1.0f
);
231 wm::SetShadowType(window
, wm::SHADOW_TYPE_NONE
);
234 gfx::RectF
GetTransformedBounds(aura::Window
* window
) {
235 gfx::Transform transform
;
236 gfx::RectF bounds
= window
->bounds();
237 transform
.Translate(bounds
.x(), bounds
.y());
238 transform
.PreconcatTransform(window
->layer()->transform());
239 transform
.Translate(-bounds
.x(), -bounds
.y());
240 transform
.TransformRect(&bounds
);
244 void TransformSplitWindowScale(aura::Window
* window
, float scale
) {
245 gfx::Transform transform
= window
->layer()->GetTargetTransform();
246 if (transform
.Scale2d() == gfx::Vector2dF(scale
, scale
))
248 AnimateTransientGroupSetter
setter(window
);
249 setter
.SetTransform(GetTransformForSplitWindow(window
, scale
));
252 void AnimateWindowTo(aura::Window
* animate_window
,
253 aura::Window
* target_window
) {
254 AnimateTransientGroupSetter
setter(animate_window
);
256 WindowOverviewState
* target_state
=
257 target_window
->GetProperty(kWindowOverviewState
);
258 setter
.SetWindowProgress(target_state
->progress
);
261 // Always returns the same target.
262 class StaticWindowTargeter
: public aura::WindowTargeter
{
264 explicit StaticWindowTargeter(aura::Window
* target
) : target_(target
) {}
265 ~StaticWindowTargeter() override
{}
268 // aura::WindowTargeter:
269 ui::EventTarget
* FindTargetForEvent(ui::EventTarget
* root
,
270 ui::Event
* event
) override
{
274 ui::EventTarget
* FindTargetForLocatedEvent(ui::EventTarget
* root
,
275 ui::LocatedEvent
* event
) override
{
279 aura::Window
* target_
;
280 DISALLOW_COPY_AND_ASSIGN(StaticWindowTargeter
);
283 class WindowOverviewModeImpl
: public WindowOverviewMode
,
284 public ui::EventHandler
,
285 public ui::CompositorAnimationObserver
,
286 public WindowListProviderObserver
{
288 WindowOverviewModeImpl(aura::Window
* container
,
289 WindowListProvider
* window_list_provider
,
290 SplitViewController
* split_view_controller
,
291 WindowOverviewModeDelegate
* delegate
)
292 : container_(container
),
293 window_list_provider_(window_list_provider
),
294 split_view_controller_(split_view_controller
),
296 scoped_targeter_(new aura::ScopedWindowTargeter(
298 scoped_ptr
<ui::EventTargeter
>(
299 new StaticWindowTargeter(container
)))),
300 dragged_window_(nullptr) {
302 container_
->set_target_handler(this);
304 // Prepare the desired transforms for all the windows, and set the initial
305 // state on the windows.
306 ComputeTerminalStatesForAllWindows();
307 SetInitialWindowStates();
309 window_list_provider_
->AddObserver(this);
312 ~WindowOverviewModeImpl() override
{
313 window_list_provider_
->RemoveObserver(this);
314 container_
->set_target_handler(container_
->delegate());
315 RemoveAnimationObserver();
316 const aura::Window::Windows
& windows
=
317 window_list_provider_
->GetWindowList();
320 for (aura::Window
* window
: windows
)
321 RestoreWindowState(window
, split_view_controller_
);
325 // Computes the transforms for all windows in both the topmost and bottom-most
326 // positions. The transforms are set in the |kWindowOverviewState| property of
328 void ComputeTerminalStatesForAllWindows() {
331 const aura::Window::Windows
& windows
=
332 window_list_provider_
->GetWindowList();
333 for (aura::Window::Windows::const_reverse_iterator iter
= windows
.rbegin();
334 iter
!= windows
.rend();
336 aura::Window
* window
= (*iter
);
337 wm::SetShadowType(window
, wm::SHADOW_TYPE_RECTANGULAR_ALWAYS_ACTIVE
);
339 WindowOverviewState
* state
= new WindowOverviewState
;
340 window
->SetProperty(kWindowOverviewState
, state
);
341 if (split_view_controller_
->IsSplitViewModeActive() &&
342 (window
== split_view_controller_
->left_window() ||
343 window
== split_view_controller_
->right_window())) {
344 // Do not let the left/right windows be scrolled.
345 gfx::Transform transform
=
346 GetTransformForSplitWindow(window
, kOverviewDefaultScale
);
347 state
->max_y
= state
->min_y
= transform
.To2dTranslation().y();
352 state
->split
= false;
353 UpdateTerminalStateForWindowAtIndex(window
, index
, windows
.size());
357 // Computes the terminal states (i.e. the transforms for the top-most and
358 // bottom-most position in the stack) for |window|. |window_count| is the
359 // number of windows in the stack, and |index| is the position of the window
360 // in the stack (0 being the front-most window).
361 void UpdateTerminalStateForWindowAtIndex(aura::Window
* window
,
363 size_t window_count
) {
364 const int kGapBetweenWindowsBottom
= 10;
365 const int kGapBetweenWindowsTop
= 5;
368 (window_count
- index
- 1) * kGapBetweenWindowsTop
+ kSystemUIHeight
;
369 int bottom
= GetScrollableHeight() - (index
* kGapBetweenWindowsBottom
);
371 WindowOverviewState
* state
= window
->GetProperty(kWindowOverviewState
);
376 state
->max_y
= bottom
- window
->bounds().y();
377 state
->progress
= 0.f
;
380 // Sets the initial position for the windows for the overview mode.
381 void SetInitialWindowStates() {
382 // The initial overview state of the topmost three windows.
383 const float kInitialProgress
[] = { 0.5f
, 0.05f
, 0.01f
};
385 const aura::Window::Windows
& windows
=
386 window_list_provider_
->GetWindowList();
387 for (aura::Window::Windows::const_reverse_iterator iter
= windows
.rbegin();
388 iter
!= windows
.rend();
390 float progress
= 0.f
;
391 aura::Window
* window
= *iter
;
392 if (split_view_controller_
->IsSplitViewModeActive() &&
393 (window
== split_view_controller_
->left_window() ||
394 window
== split_view_controller_
->right_window())) {
397 if (index
< arraysize(kInitialProgress
))
398 progress
= kInitialProgress
[index
];
402 TransientGroupSetter
setter(window
);
404 // Unset any in-progress animation.
405 setter
.AbortAllAnimations();
407 // Showing transient parent will show the transient children if any.
410 setter
.SetTransform(gfx::Transform());
411 // Setup the animation.
413 AnimateTransientGroupSetter
setter(window
);
414 setter
.SetWindowProgress(progress
);
419 aura::Window
* SelectWindowAt(ui::LocatedEvent
* event
) {
420 CHECK_EQ(container_
, event
->target());
421 // Find the old targeter to find the target of the event.
422 ui::EventTarget
* window
= container_
;
423 ui::EventTargeter
* targeter
= scoped_targeter_
->old_targeter();
424 while (!targeter
&& window
->GetParentTarget()) {
425 window
= window
->GetParentTarget();
426 targeter
= window
->GetEventTargeter();
430 aura::Window
* target
= static_cast<aura::Window
*>(
431 targeter
->FindTargetForLocatedEvent(container_
, event
));
432 while (target
&& target
->parent() != container_
)
433 target
= target
->parent();
434 aura::Window
* transient_parent
=
435 target
? wm::GetTransientParent(target
) : nullptr;
436 return transient_parent
? transient_parent
: target
;
439 // Scroll the window list by |delta_y| amount. |delta_y| is negative when
440 // scrolling up; and positive when scrolling down.
441 void DoScroll(float delta_y
) {
442 const float kEpsilon
= 1e-3f
;
443 float delta_y_p
= std::abs(delta_y
) / GetScrollableHeight();
444 const aura::Window::Windows
& windows
=
445 window_list_provider_
->GetWindowList();
447 // Scroll up. Start with the top-most (i.e. behind-most in terms of
448 // z-index) window, and try to scroll them up.
449 for (aura::Window::Windows::const_iterator iter
= windows
.begin();
450 delta_y_p
> kEpsilon
&& iter
!= windows
.end();
452 aura::Window
* window
= (*iter
);
453 WindowOverviewState
* state
= window
->GetProperty(kWindowOverviewState
);
454 if (state
->progress
> kEpsilon
) {
455 // It is possible to scroll |window| up. Scroll it up, and update
456 // |delta_y_p| for the next window.
457 float apply
= delta_y_p
* state
->progress
;
458 TransientGroupSetter
setter(window
);
459 setter
.SetWindowProgress(std::max(0.f
, state
->progress
- apply
* 3));
464 // Scroll down. Start with the bottom-most (i.e. front-most in terms of
465 // z-index) window, and try to scroll them down.
466 aura::Window::Windows::const_reverse_iterator iter
;
467 for (iter
= windows
.rbegin();
468 delta_y_p
> kEpsilon
&& iter
!= windows
.rend();
470 aura::Window
* window
= (*iter
);
471 WindowOverviewState
* state
= window
->GetProperty(kWindowOverviewState
);
472 if (1.f
- state
->progress
> kEpsilon
) {
473 // It is possible to scroll |window| down. Scroll it down, and update
474 // |delta_y_p| for the next window.
475 TransientGroupSetter
setter(window
);
476 setter
.SetWindowProgress(std::min(1.f
, state
->progress
+ delta_y_p
));
483 int GetScrollableHeight() const {
484 const float kScrollableFraction
= 0.85f
;
485 const float kScrollableFractionInSplit
= 0.5f
;
486 const float fraction
= split_view_controller_
->IsSplitViewModeActive()
487 ? kScrollableFractionInSplit
488 : kScrollableFraction
;
489 return container_
->bounds().height() * fraction
;
492 void CreateFlingerFor(const ui::GestureEvent
& event
) {
493 gfx::Vector2dF
velocity(event
.details().velocity_x(),
494 event
.details().velocity_y());
495 fling_
.reset(new ui::FlingCurve(velocity
, gfx::FrameTime::Now()));
498 void AddAnimationObserver() {
499 ui::Compositor
* compositor
= container_
->GetHost()->compositor();
500 if (!compositor
->HasAnimationObserver(this))
501 compositor
->AddAnimationObserver(this);
504 void RemoveAnimationObserver() {
505 ui::Compositor
* compositor
= container_
->GetHost()->compositor();
506 if (compositor
->HasAnimationObserver(this))
507 compositor
->RemoveAnimationObserver(this);
510 aura::Window
* GetSplitWindowDropTarget(const ui::GestureEvent
& event
) const {
511 if (!split_view_controller_
->IsSplitViewModeActive())
513 CHECK(dragged_window_
);
514 CHECK_NE(split_view_controller_
->left_window(), dragged_window_
);
515 CHECK_NE(split_view_controller_
->right_window(), dragged_window_
);
516 aura::Window
* window
= split_view_controller_
->left_window();
517 if (GetTransformedBounds(window
).Contains(event
.location()))
519 window
= split_view_controller_
->right_window();
520 if (GetTransformedBounds(window
).Contains(event
.location()))
525 void DragWindow(const ui::GestureEvent
& event
) {
526 CHECK(dragged_window_
);
527 CHECK_EQ(ui::ET_GESTURE_SCROLL_UPDATE
, event
.type());
528 CHECK(overview_toolbar_
);
529 gfx::Vector2dF dragged_distance
=
530 dragged_start_location_
- event
.location();
531 WindowOverviewState
* dragged_state
=
532 dragged_window_
->GetProperty(kWindowOverviewState
);
533 CHECK(dragged_state
);
534 gfx::Transform transform
=
535 GetTransformForState(dragged_window_
, dragged_state
);
536 transform
.Translate(-dragged_distance
.x(), 0);
537 TransientGroupSetter
setter(dragged_window_
);
538 setter
.SetTransform(transform
);
540 // Update the toolbar.
541 const int kMinDistanceForActionButtons
= 20;
542 if (fabs(dragged_distance
.x()) > kMinDistanceForActionButtons
)
543 overview_toolbar_
->ShowActionButtons();
545 overview_toolbar_
->HideActionButtons();
547 // See if the touch-point is above one of the action-buttons.
548 OverviewToolbar::ActionType new_action
=
549 overview_toolbar_
->GetHighlightAction(event
);
551 // If the touch-point is not above any of the action buttons, then highlight
552 // the close-button by default, if the user has dragged enough to close the
554 if (new_action
== OverviewToolbar::ACTION_TYPE_NONE
) {
555 if (fabs(dragged_distance
.x()) > kMinDistanceForDismissal
)
556 new_action
= OverviewToolbar::ACTION_TYPE_CLOSE
;
558 new_action
= OverviewToolbar::ACTION_TYPE_NONE
;
560 OverviewToolbar::ActionType previous_action
=
561 overview_toolbar_
->current_action();
562 overview_toolbar_
->SetHighlightAction(new_action
);
564 aura::Window
* split_drop
= GetSplitWindowDropTarget(event
);
566 // If the user has selected to get into split-view mode, then show the
567 // window with full opacity. Otherwise, fade it out as it closes. Animate
568 // the opacity if transitioning to/from the split-view button.
569 bool animate_opacity
=
570 (new_action
!= previous_action
) &&
571 ((new_action
== OverviewToolbar::ACTION_TYPE_SPLIT
) ||
572 (previous_action
== OverviewToolbar::ACTION_TYPE_SPLIT
));
573 float ratio
= std::min(
574 1.f
, std::abs(dragged_distance
.x()) / kMinDistanceForDismissal
);
576 (new_action
== OverviewToolbar::ACTION_TYPE_SPLIT
|| split_drop
)
578 : gfx::Tween::FloatValueBetween(ratio
, kMaxOpacity
, kMinOpacity
);
579 if (animate_opacity
) {
580 AnimateTransientGroupSetter
setter(dragged_window_
);
581 setter
.SetOpacity(opacity
);
583 TransientGroupSetter
setter(dragged_window_
);
584 setter
.SetOpacity(opacity
);
587 if (split_view_controller_
->IsSplitViewModeActive()) {
588 float scale
= kOverviewDefaultScale
;
589 if (split_drop
== split_view_controller_
->left_window())
590 scale
= kMaxScaleForSplitTarget
;
591 TransformSplitWindowScale(split_view_controller_
->left_window(), scale
);
593 scale
= kOverviewDefaultScale
;
594 if (split_drop
== split_view_controller_
->right_window())
595 scale
= kMaxScaleForSplitTarget
;
596 TransformSplitWindowScale(split_view_controller_
->right_window(), scale
);
600 bool ShouldCloseDragWindow(const ui::GestureEvent
& event
) const {
601 gfx::Vector2dF dragged_distance
=
602 dragged_start_location_
- event
.location();
603 if (event
.type() == ui::ET_GESTURE_SCROLL_END
)
604 return std::abs(dragged_distance
.x()) >= kMinDistanceForDismissal
;
605 CHECK_EQ(ui::ET_SCROLL_FLING_START
, event
.type());
606 const bool dragging_towards_right
= dragged_distance
.x() < 0;
607 const bool swipe_towards_right
= event
.details().velocity_x() > 0;
608 if (dragging_towards_right
!= swipe_towards_right
)
610 const float kMinVelocityForDismissal
= 500.f
;
611 return std::abs(event
.details().velocity_x()) > kMinVelocityForDismissal
;
614 void CloseDragWindow(const ui::GestureEvent
& gesture
) {
615 // Animate |dragged_window_| offscreen first, then destroy it.
617 AnimateTransientGroupSetter
setter(dragged_window_
);
619 WindowOverviewState
* dragged_state
=
620 dragged_window_
->GetProperty(kWindowOverviewState
);
621 CHECK(dragged_state
);
622 gfx::Transform transform
= dragged_window_
->layer()->transform();
623 gfx::RectF transformed_bounds
= dragged_window_
->bounds();
624 transform
.TransformRect(&transformed_bounds
);
625 float transform_x
= 0.f
;
626 if (gesture
.location().x() > dragged_start_location_
.x())
627 transform_x
= container_
->bounds().right() - transformed_bounds
.x();
629 transform_x
= -(transformed_bounds
.x() + transformed_bounds
.width());
630 transform
.Translate(transform_x
/ kOverviewDefaultScale
, 0);
632 setter
.SetOpacity(kMinOpacity
);
634 delete dragged_window_
;
635 dragged_window_
= nullptr;
638 void RestoreDragWindow() {
639 CHECK(dragged_window_
);
640 WindowOverviewState
* dragged_state
=
641 dragged_window_
->GetProperty(kWindowOverviewState
);
642 CHECK(dragged_state
);
644 AnimateTransientGroupSetter
setter(dragged_window_
);
645 setter
.SetTransform(GetTransformForState(dragged_window_
, dragged_state
));
646 setter
.SetOpacity(1.0f
);
647 dragged_window_
= nullptr;
650 void EndDragWindow(const ui::GestureEvent
& gesture
) {
651 CHECK(dragged_window_
);
652 CHECK(overview_toolbar_
);
653 OverviewToolbar::ActionType action
= overview_toolbar_
->current_action();
654 overview_toolbar_
.reset();
655 if (action
== OverviewToolbar::ACTION_TYPE_SPLIT
) {
656 delegate_
->OnSelectSplitViewWindow(
657 nullptr, dragged_window_
, dragged_window_
);
661 // If the window is dropped on one of the left/right windows in split-mode,
662 // then switch that window.
663 aura::Window
* split_drop
= GetSplitWindowDropTarget(gesture
);
665 aura::Window
* left
= split_view_controller_
->left_window();
666 aura::Window
* right
= split_view_controller_
->right_window();
667 if (left
== split_drop
)
668 left
= dragged_window_
;
670 right
= dragged_window_
;
671 delegate_
->OnSelectSplitViewWindow(left
, right
, dragged_window_
);
675 if (ShouldCloseDragWindow(gesture
))
676 CloseDragWindow(gesture
);
681 void SelectWindow(aura::Window
* window
) {
682 if (!split_view_controller_
->IsSplitViewModeActive()) {
683 delegate_
->OnSelectWindow(window
);
685 // If the selected window is one of the left/right windows, then keep the
687 if (window
== split_view_controller_
->left_window() ||
688 window
== split_view_controller_
->right_window()) {
689 delegate_
->OnSelectSplitViewWindow(
690 split_view_controller_
->left_window(),
691 split_view_controller_
->right_window(),
694 delegate_
->OnSelectWindow(window
);
700 void OnMouseEvent(ui::MouseEvent
* mouse
) override
{
701 if (mouse
->type() == ui::ET_MOUSE_PRESSED
) {
702 aura::Window
* select
= SelectWindowAt(mouse
);
705 SelectWindow(select
);
707 } else if (mouse
->type() == ui::ET_MOUSEWHEEL
) {
708 DoScroll(static_cast<ui::MouseWheelEvent
*>(mouse
)->y_offset());
712 void OnScrollEvent(ui::ScrollEvent
* scroll
) override
{
713 if (scroll
->type() == ui::ET_SCROLL
)
714 DoScroll(scroll
->y_offset());
717 void OnGestureEvent(ui::GestureEvent
* gesture
) override
{
718 if (gesture
->type() == ui::ET_GESTURE_TAP
) {
719 aura::Window
* select
= SelectWindowAt(gesture
);
721 gesture
->SetHandled();
722 SelectWindow(select
);
724 } else if (gesture
->type() == ui::ET_GESTURE_SCROLL_BEGIN
) {
725 if (std::abs(gesture
->details().scroll_x_hint()) >
726 std::abs(gesture
->details().scroll_y_hint()) * 2) {
727 dragged_start_location_
= gesture
->location();
728 dragged_window_
= SelectWindowAt(gesture
);
729 if (split_view_controller_
->IsSplitViewModeActive() &&
730 (dragged_window_
== split_view_controller_
->left_window() ||
731 dragged_window_
== split_view_controller_
->right_window())) {
732 // TODO(sad): Allow closing the left/right window. Closing one of
733 // these windows will terminate the split-view mode. Until then, do
734 // not allow closing these (since otherwise it gets into an undefined
736 dragged_window_
= nullptr;
739 if (dragged_window_
) {
740 // Show the toolbar (for closing a window, or going into split-view
741 // mode). If already in split-view mode, then do not show the 'Split'
743 overview_toolbar_
.reset(new OverviewToolbar(container_
));
744 if (!split_view_controller_
->CanActivateSplitViewMode()) {
745 overview_toolbar_
->DisableAction(
746 OverviewToolbar::ACTION_TYPE_SPLIT
);
750 } else if (gesture
->type() == ui::ET_GESTURE_SCROLL_UPDATE
) {
752 DragWindow(*gesture
);
754 DoScroll(gesture
->details().scroll_y());
755 gesture
->SetHandled();
756 } else if (gesture
->type() == ui::ET_GESTURE_SCROLL_END
) {
758 EndDragWindow(*gesture
);
759 gesture
->SetHandled();
760 } else if (gesture
->type() == ui::ET_SCROLL_FLING_START
) {
761 if (dragged_window_
) {
762 EndDragWindow(*gesture
);
764 CreateFlingerFor(*gesture
);
765 AddAnimationObserver();
767 gesture
->SetHandled();
768 } else if (gesture
->type() == ui::ET_GESTURE_TAP_DOWN
) {
771 RemoveAnimationObserver();
772 gesture
->SetHandled();
774 dragged_window_
= nullptr;
778 // ui::CompositorAnimationObserver:
779 void OnAnimationStep(base::TimeTicks timestamp
) override
{
781 gfx::Vector2dF delta
;
782 bool fling_active
= fling_
->ComputeScrollDeltaAtTime(timestamp
, &delta
);
789 RemoveAnimationObserver();
793 // WindowListProviderObserver:
794 void OnWindowStackingChangedInList() override
{
795 // Recompute the states of all windows. There isn't enough information at
796 // this point to do anything more clever.
797 ComputeTerminalStatesForAllWindows();
798 SetInitialWindowStates();
801 void OnWindowAddedToList(aura::Window
* removed_window
) override
{}
803 void OnWindowRemovedFromList(aura::Window
* removed_window
,
804 int index
) override
{
805 const aura::Window::Windows
& windows
=
806 window_list_provider_
->GetWindowList();
809 CHECK_LE(index
, static_cast<int>(windows
.size()));
811 // The back-most window has been removed. Move all the remaining windows
812 // one step backwards.
813 for (int i
= windows
.size() - 1; i
> 0; --i
) {
814 UpdateTerminalStateForWindowAtIndex(
815 windows
[i
], windows
.size() - 1 - i
, windows
.size());
816 AnimateWindowTo(windows
[i
], windows
[i
- 1]);
818 UpdateTerminalStateForWindowAtIndex(windows
.front(),
821 AnimateWindowTo(windows
.front(), removed_window
);
823 // Move all windows behind the removed window one step forwards.
824 for (int i
= 0; i
< index
- 1; ++i
) {
825 UpdateTerminalStateForWindowAtIndex(windows
[i
], windows
.size() - 1 - i
,
827 AnimateWindowTo(windows
[i
], windows
[i
+ 1]);
829 UpdateTerminalStateForWindowAtIndex(windows
[index
- 1],
830 windows
.size() - index
,
832 AnimateWindowTo(windows
[index
- 1], removed_window
);
836 const int kMinDistanceForDismissal
= 300;
837 const float kMaxOpacity
= 1.0f
;
838 const float kMinOpacity
= 0.2f
;
839 const float kMaxScaleForSplitTarget
= 0.9f
;
841 aura::Window
* container_
;
842 // Provider of the stack of windows to show in the overview mode. Not owned.
843 WindowListProvider
* window_list_provider_
;
844 SplitViewController
* split_view_controller_
;
846 WindowOverviewModeDelegate
* delegate_
;
847 scoped_ptr
<aura::ScopedWindowTargeter
> scoped_targeter_
;
848 scoped_ptr
<ui::FlingCurve
> fling_
;
850 aura::Window
* dragged_window_
;
851 gfx::Point dragged_start_location_
;
852 scoped_ptr
<OverviewToolbar
> overview_toolbar_
;
854 DISALLOW_COPY_AND_ASSIGN(WindowOverviewModeImpl
);
860 scoped_ptr
<WindowOverviewMode
> WindowOverviewMode::Create(
861 aura::Window
* container
,
862 WindowListProvider
* window_list_provider
,
863 SplitViewController
* split_view_controller
,
864 WindowOverviewModeDelegate
* delegate
) {
865 return scoped_ptr
<WindowOverviewMode
>(
866 new WindowOverviewModeImpl(container
, window_list_provider
,
867 split_view_controller
, delegate
));
870 } // namespace athena